--- /dev/null
+
+var Builder={NODEMAP:{AREA:'map',CAPTION:'table',COL:'table',COLGROUP:'table',LEGEND:'fieldset',OPTGROUP:'select',OPTION:'select',PARAM:'object',TBODY:'table',TD:'table',TFOOT:'table',TH:'table',THEAD:'table',TR:'table'},node:function(elementName){elementName=elementName.toUpperCase();var parentTag=this.NODEMAP[elementName]||'div';var parentElement=document.createElement(parentTag);try{parentElement.innerHTML="<"+elementName+"></"+elementName+">";}catch(e){}
+var element=parentElement.firstChild||null;if(element&&(element.tagName.toUpperCase()!=elementName))
+element=element.getElementsByTagName(elementName)[0];if(!element)element=document.createElement(elementName);if(!element)return;if(arguments[1])
+if(this._isStringOrNumber(arguments[1])||(arguments[1]instanceof Array)||arguments[1].tagName){this._children(element,arguments[1]);}else{var attrs=this._attributes(arguments[1]);if(attrs.length){try{parentElement.innerHTML="<"+elementName+" "+
+attrs+"></"+elementName+">";}catch(e){}
+element=parentElement.firstChild||null;if(!element){element=document.createElement(elementName);for(attr in arguments[1])
+element[attr=='class'?'className':attr]=arguments[1][attr];}
+if(element.tagName.toUpperCase()!=elementName)
+element=parentElement.getElementsByTagName(elementName)[0];}}
+if(arguments[2])
+this._children(element,arguments[2]);return element;},_text:function(text){return document.createTextNode(text);},ATTR_MAP:{'className':'class','htmlFor':'for'},_attributes:function(attributes){var attrs=[];for(attribute in attributes)
+attrs.push((attribute in this.ATTR_MAP?this.ATTR_MAP[attribute]:attribute)+'="'+attributes[attribute].toString().escapeHTML().gsub(/"/,'"')+'"');return attrs.join(" ");},_children:function(element,children){if(children.tagName){element.appendChild(children);return;}
+if(typeof children=='object'){children.flatten().each(function(e){if(typeof e=='object')
+element.appendChild(e)
+else
+if(Builder._isStringOrNumber(e))
+element.appendChild(Builder._text(e));});}else
+if(Builder._isStringOrNumber(children))
+element.appendChild(Builder._text(children));},_isStringOrNumber:function(param){return(typeof param=='string'||typeof param=='number');},build:function(html){var element=this.node('div');$(element).update(html.strip());return element.down();},dump:function(scope){if(typeof scope!='object'&&typeof scope!='function')scope=window;var tags=("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY "+"BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET "+"FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+"KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+"PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+"TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);tags.each(function(tag){scope[tag]=function(){return Builder.node.apply(Builder,[tag].concat($A(arguments)));}});}}
\ No newline at end of file
--- /dev/null
+/* Prototype-UI, version trunk
+ *
+ * Prototype-UI is freely distributable under the terms of an MIT-style license.
+ * For details, see the PrototypeUI web site: http://www.prototype-ui.com/
+ *
+ *--------------------------------------------------------------------------*/
+
+if(typeof Prototype == 'undefined' || !Prototype.Version.match("1.6"))
+ throw("Prototype-UI library require Prototype library >= 1.6.0");
+
+if (Prototype.Browser.WebKit) {
+ Prototype.Browser.WebKitVersion = parseFloat(navigator.userAgent.match(/AppleWebKit\/([\d\.\+]*)/)[1]);
+ Prototype.Browser.Safari2 = (Prototype.Browser.WebKitVersion < 420);
+}
+
+if (Prototype.Browser.IE) {
+ Prototype.Browser.IEVersion = parseFloat(navigator.appVersion.split(';')[1].strip().split(' ')[1]);
+ Prototype.Browser.IE6 = Prototype.Browser.IEVersion == 6;
+ Prototype.Browser.IE7 = Prototype.Browser.IEVersion == 7;
+}
+
+Prototype.falseFunction = function() { return false };
+Prototype.trueFunction = function() { return true };
+
+/*
+Namespace: UI
+
+ Introduction:
+ Prototype-UI is a library of user interface components based on the Prototype framework.
+ Its aim is to easilly improve user experience in web applications.
+
+ It also provides utilities to help developers.
+
+ Guideline:
+ - Prototype conventions are followed
+ - Everything should be unobstrusive
+ - All components are themable with CSS stylesheets, various themes are provided
+
+ Warning:
+ Prototype-UI is still under deep development, this release is targeted to developers only.
+ All interfaces are subjects to changes, suggestions are welcome.
+
+ DO NOT use it in production for now.
+
+ Authors:
+ - Sébastien Gruhier, <http://www.xilinus.com>
+ - Samuel Lebeau, <http://gotfresh.info>
+*/
+
+var UI = {
+ Abstract: { },
+ Ajax: { }
+};
+Object.extend(Class.Methods, {
+ extend: Object.extend.methodize(),
+
+ addMethods: Class.Methods.addMethods.wrap(function(proceed, source) {
+ // ensure we are not trying to add null or undefined
+ if (!source) return this;
+
+ // no callback, vanilla way
+ if (!source.hasOwnProperty('methodsAdded'))
+ return proceed(source);
+
+ var callback = source.methodsAdded;
+ delete source.methodsAdded;
+ proceed(source);
+ callback.call(source, this);
+ source.methodsAdded = callback;
+
+ return this;
+ }),
+
+ addMethod: function(name, lambda) {
+ var methods = {};
+ methods[name] = lambda;
+ return this.addMethods(methods);
+ },
+
+ method: function(name) {
+ return this.prototype[name].valueOf();
+ },
+
+ classMethod: function() {
+ $A(arguments).flatten().each(function(method) {
+ this[method] = (function() {
+ return this[method].apply(this, arguments);
+ }).bind(this.prototype);
+ }, this);
+ return this;
+ },
+
+ // prevent any call to this method
+ undefMethod: function(name) {
+ this.prototype[name] = undefined;
+ return this;
+ },
+
+ // remove the class' own implementation of this method
+ removeMethod: function(name) {
+ delete this.prototype[name];
+ return this;
+ },
+
+ aliasMethod: function(newName, name) {
+ this.prototype[newName] = this.prototype[name];
+ return this;
+ },
+
+ aliasMethodChain: function(target, feature) {
+ feature = feature.camelcase();
+
+ this.aliasMethod(target+"Without"+feature, target);
+ this.aliasMethod(target, target+"With"+feature);
+
+ return this;
+ }
+});
+Object.extend(Number.prototype, {
+ // Snap a number to a grid
+ snap: function(round) {
+ return parseInt(round == 1 ? this : (this / round).floor() * round);
+ }
+});
+/*
+Interface: String
+
+*/
+
+Object.extend(String.prototype, {
+ camelcase: function() {
+ var string = this.dasherize().camelize();
+ return string.charAt(0).toUpperCase() + string.slice(1);
+ },
+
+ /*
+ Method: makeElement
+ toElement is unfortunately already taken :/
+
+ Transforms html string into an extended element or null (when failed)
+
+ > '<li><a href="#">some text</a></li>'.makeElement(); // => LI href#
+ > '<img src="foo" id="bar" /><img src="bar" id="bar" />'.makeElement(); // => IMG#foo (first one)
+
+ Returns:
+ Extended element
+
+ */
+ makeElement: function() {
+ var wrapper = new Element('div'); wrapper.innerHTML = this;
+ return wrapper.down();
+ }
+});
+Object.extend(Array.prototype, {
+ empty: function() {
+ return !this.length;
+ },
+
+ extractOptions: function() {
+ return this.last().constructor === Object ? this.pop() : { };
+ },
+
+ removeAt: function(index) {
+ var object = this[index];
+ this.splice(index, 1);
+ return object;
+ },
+
+ remove: function(object) {
+ var index;
+ while ((index = this.indexOf(object)) != -1)
+ this.removeAt(index);
+ return object;
+ },
+
+ insert: function(index) {
+ var args = $A(arguments);
+ args.shift();
+ this.splice.apply(this, [ index, 0 ].concat(args));
+ return this;
+ }
+});
+Element.addMethods({
+ getScrollDimensions: function(element) {
+ return {
+ width: element.scrollWidth,
+ height: element.scrollHeight
+ }
+ },
+
+ getScrollOffset: function(element) {
+ return Element._returnOffset(element.scrollLeft, element.scrollTop);
+ },
+
+ setScrollOffset: function(element, offset) {
+ element = $(element);
+ if (arguments.length == 3)
+ offset = { left: offset, top: arguments[2] };
+ element.scrollLeft = offset.left;
+ element.scrollTop = offset.top;
+ return element;
+ },
+
+ // returns "clean" numerical style (without "px") or null if style can not be resolved
+ // or is not numeric
+ getNumStyle: function(element, style) {
+ var value = parseFloat($(element).getStyle(style));
+ return isNaN(value) ? null : value;
+ },
+
+ // by Tobie Langel (http://tobielangel.com/2007/5/22/prototype-quick-tip)
+ appendText: function(element, text) {
+ element = $(element);
+ text = String.interpret(text);
+ element.appendChild(document.createTextNode(text));
+ return element;
+ }
+});
+
+document.whenReady = function(callback) {
+ if (document.loaded)
+ callback.call(document);
+ else
+ document.observe('dom:loaded', callback);
+};
+
+Object.extend(document.viewport, {
+ // Alias this method for consistency
+ getScrollOffset: document.viewport.getScrollOffsets,
+
+ setScrollOffset: function(offset) {
+ Element.setScrollOffset(Prototype.Browser.WebKit ? document.body : document.documentElement, offset);
+ },
+
+ getScrollDimensions: function() {
+ return Element.getScrollDimensions(Prototype.Browser.WebKit ? document.body : document.documentElement);
+ }
+});
+/*
+Interface: UI.Options
+ Mixin to handle *options* argument in initializer pattern.
+
+ TODO: find a better example than Circle that use an imaginary Point function,
+ this example should be used in tests too.
+
+ It assumes class defines a property called *options*, containing
+ default options values.
+
+ Instances hold their own *options* property after a first call to <setOptions>.
+
+ Example:
+ > var Circle = Class.create(UI.Options, {
+ >
+ > // default options
+ > options: {
+ > radius: 1,
+ > origin: Point(0, 0)
+ > },
+ >
+ > // common usage is to call setOptions in initializer
+ > initialize: function(options) {
+ > this.setOptions(options);
+ > }
+ > });
+ >
+ > var circle = new Circle({ origin: Point(1, 4) });
+ >
+ > circle.options
+ > // => { radius: 1, origin: Point(1,4) }
+
+ Accessors:
+ There are builtin methods to automatically write options accessors. All those
+ methods can take either an array of option names nor option names as arguments.
+ Notice that those methods won't override an accessor method if already present.
+
+ * <optionsGetter> creates getters
+ * <optionsSetter> creates setters
+ * <optionsAccessor> creates both getters and setters
+
+ Common usage is to invoke them on a class to create accessors for all instances
+ of this class.
+ Invoking those methods on a class has the same effect as invoking them on the class prototype.
+ See <classMethod> for more details.
+
+ Example:
+ > // Creates getter and setter for the "radius" options of circles
+ > Circle.optionsAccessor('radius');
+ >
+ > circle.setRadius(4);
+ > // 4
+ >
+ > circle.getRadius();
+ > // => 4 (circle.options.radius)
+
+ Inheritance support:
+ Subclasses can refine default *options* values, after a first instance call on setOptions,
+ *options* attribute will hold all default options values coming from the inheritance hierarchy.
+*/
+
+(function() {
+ UI.Options = {
+ methodsAdded: function(klass) {
+ klass.classMethod($w(' setOptions allOptions optionsGetter optionsSetter optionsAccessor '));
+ },
+
+ // Group: Methods
+
+ /*
+ Method: setOptions
+ Extends object's *options* property with the given object
+ */
+ setOptions: function(options) {
+ if (!this.hasOwnProperty('options'))
+ this.options = this.allOptions();
+
+ this.options = Object.extend(this.options, options || {});
+ },
+
+ /*
+ Method: allOptions
+ Computes the complete default options hash made by reverse extending all superclasses
+ default options.
+
+ > Widget.prototype.allOptions();
+ */
+ allOptions: function() {
+ var superclass = this.constructor.superclass, ancestor = superclass && superclass.prototype;
+ return (ancestor && ancestor.allOptions) ?
+ Object.extend(ancestor.allOptions(), this.options) :
+ Object.clone(this.options);
+ },
+
+ /*
+ Method: optionsGetter
+ Creates default getters for option names given as arguments.
+ With no argument, creates getters for all option names.
+ */
+ optionsGetter: function() {
+ addOptionsAccessors(this, arguments, false);
+ },
+
+ /*
+ Method: optionsSetter
+ Creates default setters for option names given as arguments.
+ With no argument, creates setters for all option names.
+ */
+ optionsSetter: function() {
+ addOptionsAccessors(this, arguments, true);
+ },
+
+ /*
+ Method: optionsAccessor
+ Creates default getters/setters for option names given as arguments.
+ With no argument, creates accessors for all option names.
+ */
+ optionsAccessor: function() {
+ this.optionsGetter.apply(this, arguments);
+ this.optionsSetter.apply(this, arguments);
+ }
+ };
+
+ // Internal
+ function addOptionsAccessors(receiver, names, areSetters) {
+ names = $A(names).flatten();
+
+ if (names.empty())
+ names = Object.keys(receiver.allOptions());
+
+ names.each(function(name) {
+ var accessorName = (areSetters ? 'set' : 'get') + name.camelcase();
+
+ receiver[accessorName] = receiver[accessorName] || (areSetters ?
+ // Setter
+ function(value) { return this.options[name] = value } :
+ // Getter
+ function() { return this.options[name] });
+ });
+ }
+})();
+/*
+ Class: UI.Carousel
+
+ Main class to handle a carousel of elements in a page. A carousel :
+ * could be vertical or horizontal
+ * works with liquid layout
+ * is designed by CSS
+
+ Assumptions:
+ * Elements should be from the same size
+
+ Example:
+ > ...
+ > <div id="horizontal_carousel">
+ > <div class="previous_button"></div>
+ > <div class="container">
+ > <ul>
+ > <li> What ever you like</li>
+ > </ul>
+ > </div>
+ > <div class="next_button"></div>
+ > </div>
+ > <script>
+ > new UI.Carousel("horizontal_carousel");
+ > </script>
+ > ...
+*/
+UI.Carousel = Class.create(UI.Options, {
+ // Group: Options
+ options: {
+ // Property: direction
+ // Can be horizontal or vertical, horizontal by default
+ direction : "horizontal",
+
+ // Property: previousButton
+ // Selector of previous button inside carousel element, ".previous_button" by default,
+ // set it to false to ignore previous button
+ previousButton : ".previous_button",
+
+ // Property: nextButton
+ // Selector of next button inside carousel element, ".next_button" by default,
+ // set it to false to ignore next button
+ nextButton : ".next_button",
+
+ // Property: container
+ // Selector of carousel container inside carousel element, ".container" by default,
+ container : ".container",
+
+ // Property: scrollInc
+ // Define the maximum number of elements that gonna scroll each time, auto by default
+ scrollInc : "auto",
+
+ // Property: disabledButtonSuffix
+ // Define the suffix classanme used when a button get disabled, to '_disabled' by default
+ // Previous button classname will be previous_button_disabled
+ disabledButtonSuffix : '_disabled',
+
+ // Property: overButtonSuffix
+ // Define the suffix classanme used when a button has a rollover status, '_over' by default
+ // Previous button classname will be previous_button_over
+ overButtonSuffix : '_over'
+ },
+
+ /*
+ Group: Attributes
+
+ Property: element
+ DOM element containing the carousel
+
+ Property: id
+ DOM id of the carousel's element
+
+ Property: container
+ DOM element containing the carousel's elements
+
+ Property: elements
+ Array containing the carousel's elements as DOM elements
+
+ Property: previousButton
+ DOM id of the previous button
+
+ Property: nextButton
+ DOM id of the next button
+
+ Property: posAttribute
+ Define if the positions are from left or top
+
+ Property: dimAttribute
+ Define if the dimensions are horizontal or vertical
+
+ Property: elementSize
+ Size of each element, it's an integer
+
+ Property: nbVisible
+ Number of visible elements, it's a float
+
+ Property: animating
+ Define whether the carousel is in animation or not
+ */
+
+ /*
+ Group: Events
+ List of events fired by a carousel
+
+ Notice: Carousel custom events are automatically namespaced in "carousel:" (see Prototype custom events).
+
+ Examples:
+ This example will observe all carousels
+ > document.observe('carousel:scroll:ended', function(event) {
+ > alert("Carousel with id " + event.memo.carousel.id + " has just been scrolled");
+ > });
+
+ This example will observe only this carousel
+ > new UI.Carousel('horizontal_carousel').observe('scroll:ended', function(event) {
+ > alert("Carousel with id " + event.memo.carousel.id + " has just been scrolled");
+ > });
+
+ Property: previousButton:enabled
+ Fired when the previous button has just been enabled
+
+ Property: previousButton:disabled
+ Fired when the previous button has just been disabled
+
+ Property: nextButton:enabled
+ Fired when the next button has just been enabled
+
+ Property: nextButton:disabled
+ Fired when the next button has just been disabled
+
+ Property: scroll:started
+ Fired when a scroll has just started
+
+ Property: scroll:ended
+ Fired when a scroll has been done,
+ memo.shift = number of elements scrolled, it's a float
+
+ Property: sizeUpdated
+ Fired when the carousel size has just been updated.
+ Tips: memo.carousel.currentSize() = the new carousel size
+ */
+
+ // Group: Constructor
+
+ /*
+ Method: initialize
+ Constructor function, should not be called directly
+
+ Parameters:
+ element - DOM element
+ options - (Hash) list of optional parameters
+
+ Returns:
+ this
+ */
+ initialize: function(element, options) {
+ this.setOptions(options);
+ this.element = $(element);
+ this.id = this.element.id;
+ this.container = this.element.down(this.options.container).firstDescendant();
+ this.elements = this.container.childElements();
+ this.previousButton = this.options.previousButton == false ? null : this.element.down(this.options.previousButton);
+ this.nextButton = this.options.nextButton == false ? null : this.element.down(this.options.nextButton);
+
+ this.posAttribute = (this.options.direction == "horizontal" ? "left" : "top");
+ this.dimAttribute = (this.options.direction == "horizontal" ? "width" : "height");
+
+ this.elementSize = this.computeElementSize();
+ this.nbVisible = this.currentSize() / this.elementSize;
+
+ var scrollInc = this.options.scrollInc;
+ if (scrollInc == "auto")
+ scrollInc = Math.floor(this.nbVisible);
+ [ this.previousButton, this.nextButton ].each(function(button) {
+ if (!button) return;
+ var className = (button == this.nextButton ? "next_button" : "previous_button") + this.options.overButtonSuffix;
+ button.clickHandler = this.scroll.bind(this, (button == this.nextButton ? -1 : 1) * scrollInc * this.elementSize);
+ button.observe("click", button.clickHandler)
+ .observe("mouseover", function() {button.addClassName(className)}.bind(this))
+ .observe("mouseout", function() {button.removeClassName(className)}.bind(this));
+ }, this);
+ this.updateButtons();
+ },
+
+ // Group: Destructor
+
+ /*
+ Method: destroy
+ Cleans up DOM and memory
+ */
+ destroy: function($super) {
+ [ this.previousButton, this.nextButton ].each(function(button) {
+ if (!button) return;
+ button.stopObserving("click", button.clickHandler);
+ }, this);
+ this.element.remove();
+ this.fire('destroyed');
+ },
+
+ // Group: Event handling
+
+ /*
+ Method: fire
+ Fires a carousel custom event automatically namespaced in "carousel:" (see Prototype custom events).
+ The memo object contains a "carousel" property referring to the carousel.
+
+ Example:
+ > document.observe('carousel:scroll:ended', function(event) {
+ > alert("Carousel with id " + event.memo.carousel.id + " has just been scrolled");
+ > });
+
+ Parameters:
+ eventName - an event name
+ memo - a memo object
+
+ Returns:
+ fired event
+ */
+ fire: function(eventName, memo) {
+ memo = memo || { };
+ memo.carousel = this;
+ return this.element.fire('carousel:' + eventName, memo);
+ },
+
+ /*
+ Method: observe
+ Observe a carousel event with a handler function automatically bound to the carousel
+
+ Parameters:
+ eventName - an event name
+ handler - a handler function
+
+ Returns:
+ this
+ */
+ observe: function(eventName, handler) {
+ this.element.observe('carousel:' + eventName, handler.bind(this));
+ return this;
+ },
+
+ /*
+ Method: stopObserving
+ Unregisters a carousel event, it must take the same parameters as this.observe (see Prototype stopObserving).
+
+ Parameters:
+ eventName - an event name
+ handler - a handler function
+
+ Returns:
+ this
+ */
+ stopObserving: function(eventName, handler) {
+ this.element.stopObserving('carousel:' + eventName, handler);
+ return this;
+ },
+
+ // Group: Actions
+
+ /*
+ Method: checkScroll
+ Check scroll position to avoid unused space at right or bottom
+
+ Parameters:
+ position - position to check
+ updatePosition - should the container position be updated ? true/false
+
+ Returns:
+ position
+ */
+ checkScroll: function(position, updatePosition) {
+ if (position > 0)
+ position = 0;
+ else {
+ var limit = this.elements.last().positionedOffset()[this.posAttribute] + this.elementSize;
+ var carouselSize = this.currentSize();
+
+ if (position + limit < carouselSize)
+ position += carouselSize - (position + limit);
+ position = Math.min(position, 0);
+ }
+ if (updatePosition)
+ this.container.style[this.posAttribute] = position + "px";
+
+ return position;
+ },
+
+ /*
+ Method: scroll
+ Scrolls carousel from maximum deltaPixel
+
+ Parameters:
+ deltaPixel - a float
+
+ Returns:
+ this
+ */
+ scroll: function(deltaPixel) {
+ if (this.animating)
+ return this;
+
+ // Compute new position
+ var position = this.currentPosition() + deltaPixel;
+
+ // Check bounds
+ position = this.checkScroll(position, false);
+
+ // Compute shift to apply
+ deltaPixel = position - this.currentPosition();
+ if (deltaPixel != 0) {
+ this.animating = true;
+ this.fire("scroll:started");
+
+ var that = this;
+ // Move effects
+ this.container.morph("opacity:0.5", {duration: 0.2, afterFinish: function() {
+ that.container.morph(that.posAttribute + ": " + position + "px", {
+ duration: 0.4,
+ delay: 0.2,
+ afterFinish: function() {
+ that.container.morph("opacity:1", {
+ duration: 0.2,
+ afterFinish: function() {
+ that.animating = false;
+ that.updateButtons()
+ .fire("scroll:ended", { shift: deltaPixel / that.currentSize() });
+ }
+ });
+ }
+ });
+ }});
+ }
+ return this;
+ },
+
+ /*
+ Method: scrollTo
+ Scrolls carousel, so that element with specified index is the left-most.
+ This method is convenient when using carousel in a tabbed navigation.
+ Clicking on first tab should scroll first container into view, clicking on a fifth - fifth one, etc.
+ Indexing starts with 0.
+
+ Parameters:
+ Index of an element which will be a left-most visible in the carousel
+
+ Returns:
+ this
+ */
+ scrollTo: function(index) {
+ if (this.animating || index < 0 || index > this.elements.length || index == this.currentIndex() || isNaN(parseInt(index)))
+ return this;
+ return this.scroll((this.currentIndex() - index) * this.elementSize);
+ },
+
+ /*
+ Method: updateButtons
+ Update buttons status to enabled or disabled
+ Them status is defined by classNames and fired as carousel's custom events
+
+ Returns:
+ this
+ */
+ updateButtons: function() {
+ this.updatePreviousButton();
+ this.updateNextButton();
+ return this;
+ },
+
+ updatePreviousButton: function() {
+ var position = this.currentPosition();
+ var previousClassName = "previous_button" + this.options.disabledButtonSuffix;
+
+ if (this.previousButton.hasClassName(previousClassName) && position != 0) {
+ this.previousButton.removeClassName(previousClassName);
+ this.fire('previousButton:enabled');
+ }
+ if (!this.previousButton.hasClassName(previousClassName) && position == 0) {
+ this.previousButton.addClassName(previousClassName);
+ this.fire('previousButton:disabled');
+ }
+ },
+
+ updateNextButton: function() {
+ var lastPosition = this.currentLastPosition();
+ var size = this.currentSize();
+ var nextClassName = "next_button" + this.options.disabledButtonSuffix;
+
+ if (this.nextButton.hasClassName(nextClassName) && lastPosition != size) {
+ this.nextButton.removeClassName(nextClassName);
+ this.fire('nextButton:enabled');
+ }
+ if (!this.nextButton.hasClassName(nextClassName) && lastPosition == size) {
+ this.nextButton.addClassName(nextClassName);
+ this.fire('nextButton:disabled');
+ }
+ },
+
+ // Group: Size and Position
+
+ /*
+ Method: computeElementSize
+ Return elements size in pixel, height or width depends on carousel orientation.
+
+ Returns:
+ an integer value
+ */
+ computeElementSize: function() {
+ return this.elements.first().getDimensions()[this.dimAttribute];
+ },
+
+ /*
+ Method: currentIndex
+ Returns current visible index of a carousel.
+ For example, a horizontal carousel with image #3 on left will return 3 and with half of image #3 will return 3.5
+ Don't forget that the first image have an index 0
+
+ Returns:
+ a float value
+ */
+ currentIndex: function() {
+ return - this.currentPosition() / this.elementSize;
+ },
+
+ /*
+ Method: currentLastPosition
+ Returns the current position from the end of the last element. This value is in pixel.
+
+ Returns:
+ an integer value, if no images a present it will return 0
+ */
+ currentLastPosition: function() {
+ if (this.container.childElements().empty())
+ return 0;
+ return this.currentPosition() +
+ this.elements.last().positionedOffset()[this.posAttribute] +
+ this.elementSize;
+ },
+
+ /*
+ Method: currentPosition
+ Returns the current position in pixel.
+ Tips: To get the position in elements use currentIndex()
+
+ Returns:
+ an integer value
+ */
+ currentPosition: function() {
+ return this.container.getNumStyle(this.posAttribute);
+ },
+
+ /*
+ Method: currentSize
+ Returns the current size of the carousel in pixel
+
+ Returns:
+ Carousel's size in pixel
+ */
+ currentSize: function() {
+ return this.container.parentNode.getDimensions()[this.dimAttribute];
+ },
+
+ /*
+ Method: updateSize
+ Should be called if carousel size has been changed (usually called with a liquid layout)
+
+ Returns:
+ this
+ */
+ updateSize: function() {
+ this.nbVisible = this.currentSize() / this.elementSize;
+ var scrollInc = this.options.scrollInc;
+ if (scrollInc == "auto")
+ scrollInc = Math.floor(this.nbVisible);
+
+ [ this.previousButton, this.nextButton ].each(function(button) {
+ if (!button) return;
+ button.stopObserving("click", button.clickHandler);
+ button.clickHandler = this.scroll.bind(this, (button == this.nextButton ? -1 : 1) * scrollInc * this.elementSize);
+ button.observe("click", button.clickHandler);
+ }, this);
+
+ this.checkScroll(this.currentPosition(), true);
+ this.updateButtons().fire('sizeUpdated');
+ return this;
+ }
+});
+/*
+ Class: UI.Ajax.Carousel
+
+ Gives the AJAX power to carousels. An AJAX carousel :
+ * Use AJAX to add new elements on the fly
+
+ Example:
+ > new UI.Ajax.Carousel("horizontal_carousel",
+ > {url: "get-more-elements", elementSize: 250});
+*/
+UI.Ajax.Carousel = Class.create(UI.Carousel, {
+ // Group: Options
+ //
+ // Notice:
+ // It also include of all carousel's options
+ options: {
+ // Property: elementSize
+ // Required, it define the size of all elements
+ elementSize : -1,
+
+ // Property: url
+ // Required, it define the URL used by AJAX carousel to request new elements details
+ url : null
+ },
+
+ /*
+ Group: Attributes
+
+ Notice:
+ It also include of all carousel's attributes
+
+ Property: elementSize
+ Size of each elements, it's an integer
+
+ Property: endIndex
+ Index of the last loaded element
+
+ Property: hasMore
+ Flag to define if there's still more elements to load
+
+ Property: requestRunning
+ Define whether a request is processing or not
+
+ Property: updateHandler
+ Callback to update carousel, usually used after request success
+
+ Property: url
+ URL used to request additional elements
+ */
+
+ /*
+ Group: Events
+ List of events fired by an AJAX carousel, it also include of all carousel's custom events
+
+ Property: request:started
+ Fired when the request has just started
+
+ Property: request:ended
+ Fired when the request has succeed
+ */
+
+ // Group: Constructor
+
+ /*
+ Method: initialize
+ Constructor function, should not be called directly
+
+ Parameters:
+ element - DOM element
+ options - (Hash) list of optional parameters
+
+ Returns:
+ this
+ */
+ initialize: function($super, element, options) {
+ if (!options.url)
+ throw("url option is required for UI.Ajax.Carousel");
+ if (!options.elementSize)
+ throw("elementSize option is required for UI.Ajax.Carousel");
+
+ $super(element, options);
+
+ this.endIndex = 0;
+ this.hasMore = true;
+
+ // Cache handlers
+ this.updateHandler = this.update.bind(this);
+ this.updateAndScrollHandler = function(nbElements, transport, json) {
+ this.update(transport, json);
+ this.scroll(nbElements);
+ }.bind(this);
+
+ // Run first ajax request to fill the carousel
+ this.runRequest.bind(this).defer({parameters: {from: 0, to: Math.floor(this.nbVisible)}, onSuccess: this.updateHandler});
+ },
+
+ // Group: Actions
+
+ /*
+ Method: runRequest
+ Request the new elements details
+
+ Parameters:
+ options - (Hash) list of optional parameters
+
+ Returns:
+ this
+ */
+ runRequest: function(options) {
+ this.requestRunning = true;
+ //alert("Asking for: " + options.parameters.from + " - " + options.parameters.to);
+ new Ajax.Request(this.options.url, Object.extend({method: "GET"}, options));
+ this.fire("request:started");
+ return this;
+ },
+
+ /*
+ Method: scroll
+ Scrolls carousel from maximum deltaPixel
+
+ Parameters:
+ deltaPixel - a float
+
+ Returns:
+ this
+ */
+ scroll: function($super, deltaPixel) {
+ if (this.animating || this.requestRunning)
+ return this;
+
+ var nbElements = (-deltaPixel) / this.elementSize;
+ // Check if there is not enough
+ if (this.hasMore && nbElements > 0 && this.currentIndex() + this.nbVisible + nbElements - 1 > this.endIndex) {
+ var from = this.endIndex + 1;
+ var to = Math.floor(from + this.nbVisible - 1);
+ this.runRequest({parameters: {from: from, to: to}, onSuccess: this.updateAndScrollHandler.curry(deltaPixel).bind(this)});
+ return this;
+ }
+ else
+ $super(deltaPixel);
+ },
+
+ /*
+ Method: update
+ Update the carousel
+
+ Parameters:
+ transport - XMLHttpRequest object
+ json - JSON object
+
+ Returns:
+ this
+ */
+ update: function(transport, json) {
+ this.requestRunning = false;
+ this.fire("request:ended");
+ if (!json)
+ json = transport.responseJSON;
+ this.hasMore = json.more;
+
+ this.endIndex = Math.max(this.endIndex, json.to);
+ this.elements = this.container.insert({bottom: json.html}).childElements();
+ return this.updateButtons();
+ },
+
+ // Group: Size and Position
+
+ /*
+ Method: computeElementSize
+ Return elements size in pixel
+
+ Returns:
+ an integer value
+ */
+ computeElementSize: function() {
+ return this.options.elementSize;
+ },
+
+ /*
+ Method: updateSize
+ Should be called if carousel size has been changed (usually called with a liquid layout)
+
+ Returns:
+ this
+ */
+ updateSize: function($super) {
+ var nbVisible = this.nbVisible;
+ $super();
+ // If we have enough space for at least a new element
+ if (Math.floor(this.nbVisible) - Math.floor(nbVisible) >= 1 && this.hasMore) {
+ if (this.currentIndex() + Math.floor(this.nbVisible) >= this.endIndex) {
+ var nbNew = Math.floor(this.currentIndex() + Math.floor(this.nbVisible) - this.endIndex);
+ this.runRequest({parameters: {from: this.endIndex + 1, to: this.endIndex + nbNew}, onSuccess: this.updateHandler});
+ }
+ }
+ return this;
+ },
+
+ updateNextButton: function($super) {
+ var lastPosition = this.currentLastPosition();
+ var size = this.currentSize();
+ var nextClassName = "next_button" + this.options.disabledButtonSuffix;
+
+ if (this.nextButton.hasClassName(nextClassName) && lastPosition != size) {
+ this.nextButton.removeClassName(nextClassName);
+ this.fire('nextButton:enabled');
+ }
+ if (!this.nextButton.hasClassName(nextClassName) && lastPosition == size && !this.hasMore) {
+ this.nextButton.addClassName(nextClassName);
+ this.fire('nextButton:disabled');
+ }
+ }
+});
--- /dev/null
+/**
+ * Copyright 2006, David Spurr (http://www.defusion.org.uk/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * * Neither the name of the David Spurr nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * See scriptaculous.js for full scriptaculous licence
+ */
+
+var CropDraggable=Class.create();
+Object.extend(Object.extend(CropDraggable.prototype,Draggable.prototype),{initialize:function(_1){
+this.options=Object.extend({drawMethod:function(){
+}},arguments[1]||{});
+this.element=$(_1);
+this.handle=this.element;
+this.delta=this.currentDelta();
+this.dragging=false;
+this.eventMouseDown=this.initDrag.bindAsEventListener(this);
+Event.observe(this.handle,"mousedown",this.eventMouseDown);
+Draggables.register(this);
+},draw:function(_2){
+var _3=Position.cumulativeOffset(this.element);
+var d=this.currentDelta();
+_3[0]-=d[0];
+_3[1]-=d[1];
+var p=[0,1].map(function(i){
+return (_2[i]-_3[i]-this.offset[i]);
+}.bind(this));
+this.options.drawMethod(p);
+}});
+var Cropper={};
+Cropper.Img=Class.create();
+Cropper.Img.prototype={initialize:function(_7,_8){
+this.options=Object.extend({ratioDim:{x:0,y:0},minWidth:0,minHeight:0,displayOnInit:false,onEndCrop:Prototype.emptyFunction,captureKeys:true,onloadCoords:null,maxWidth:0,maxHeight:0},_8||{});
+this.img=$(_7);
+this.clickCoords={x:0,y:0};
+this.dragging=false;
+this.resizing=false;
+this.isWebKit=/Konqueror|Safari|KHTML/.test(navigator.userAgent);
+this.isIE=/MSIE/.test(navigator.userAgent);
+this.isOpera8=/Opera\s[1-8]/.test(navigator.userAgent);
+this.ratioX=0;
+this.ratioY=0;
+this.attached=false;
+this.fixedWidth=(this.options.maxWidth>0&&(this.options.minWidth>=this.options.maxWidth));
+this.fixedHeight=(this.options.maxHeight>0&&(this.options.minHeight>=this.options.maxHeight));
+if(typeof this.img=="undefined"){
+return;
+}
+if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0){
+var _c=this.getGCD(this.options.ratioDim.x,this.options.ratioDim.y);
+this.ratioX=this.options.ratioDim.x/_c;
+this.ratioY=this.options.ratioDim.y/_c;
+}
+this.subInitialize();
+if(this.img.complete||this.isWebKit){
+this.onLoad();
+}else{
+Event.observe(this.img,"load",this.onLoad.bindAsEventListener(this));
+}
+},getGCD:function(a,b){
+if(b==0){
+return a;
+}
+return this.getGCD(b,a%b);
+},onLoad:function(){
+var _f="imgCrop_";
+var _10=this.img.parentNode;
+var _11="";
+if(this.isOpera8){
+_11=" opera8";
+}
+this.imgWrap=Builder.node("div",{"class":_f+"wrap"+_11});
+this.north=Builder.node("div",{"class":_f+"overlay "+_f+"north"},[Builder.node("span")]);
+this.east=Builder.node("div",{"class":_f+"overlay "+_f+"east"},[Builder.node("span")]);
+this.south=Builder.node("div",{"class":_f+"overlay "+_f+"south"},[Builder.node("span")]);
+this.west=Builder.node("div",{"class":_f+"overlay "+_f+"west"},[Builder.node("span")]);
+var _12=[this.north,this.east,this.south,this.west];
+this.dragArea=Builder.node("div",{"class":_f+"dragArea"},_12);
+this.handleN=Builder.node("div",{"class":_f+"handle "+_f+"handleN"});
+this.handleNE=Builder.node("div",{"class":_f+"handle "+_f+"handleNE"});
+this.handleE=Builder.node("div",{"class":_f+"handle "+_f+"handleE"});
+this.handleSE=Builder.node("div",{"class":_f+"handle "+_f+"handleSE"});
+this.handleS=Builder.node("div",{"class":_f+"handle "+_f+"handleS"});
+this.handleSW=Builder.node("div",{"class":_f+"handle "+_f+"handleSW"});
+this.handleW=Builder.node("div",{"class":_f+"handle "+_f+"handleW"});
+this.handleNW=Builder.node("div",{"class":_f+"handle "+_f+"handleNW"});
+this.selArea=Builder.node("div",{"class":_f+"selArea"},[Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeNorth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeEast"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeSouth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeWest"},[Builder.node("span")]),this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW,Builder.node("div",{"class":_f+"clickArea"})]);
+this.imgWrap.appendChild(this.img);
+this.imgWrap.appendChild(this.dragArea);
+this.dragArea.appendChild(this.selArea);
+this.dragArea.appendChild(Builder.node("div",{"class":_f+"clickArea"}));
+_10.appendChild(this.imgWrap);
+this.startDragBind=this.startDrag.bindAsEventListener(this);
+Event.observe(this.dragArea,"mousedown",this.startDragBind);
+this.onDragBind=this.onDrag.bindAsEventListener(this);
+Event.observe(document,"mousemove",this.onDragBind);
+this.endCropBind=this.endCrop.bindAsEventListener(this);
+Event.observe(document,"mouseup",this.endCropBind);
+this.resizeBind=this.startResize.bindAsEventListener(this);
+this.handles=[this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW];
+this.registerHandles(true);
+if(this.options.captureKeys){
+this.keysBind=this.handleKeys.bindAsEventListener(this);
+Event.observe(document,"keypress",this.keysBind);
+}
+new CropDraggable(this.selArea,{drawMethod:this.moveArea.bindAsEventListener(this)});
+this.setParams();
+},registerHandles:function(_13){
+for(var i=0;i<this.handles.length;i++){
+var _15=$(this.handles[i]);
+if(_13){
+var _16=false;
+if(this.fixedWidth&&this.fixedHeight){
+_16=true;
+}else{
+if(this.fixedWidth||this.fixedHeight){
+var _17=_15.className.match(/([S|N][E|W])$/);
+var _18=_15.className.match(/(E|W)$/);
+var _19=_15.className.match(/(N|S)$/);
+if(_17){
+_16=true;
+}else{
+if(this.fixedWidth&&_18){
+_16=true;
+}else{
+if(this.fixedHeight&&_19){
+_16=true;
+}
+}
+}
+}
+}
+if(_16){
+_15.hide();
+}else{
+Event.observe(_15,"mousedown",this.resizeBind);
+}
+}else{
+_15.show();
+Event.stopObserving(_15,"mousedown",this.resizeBind);
+}
+}
+},setParams:function(){
+this.imgW=this.img.width;
+this.imgH=this.img.height;
+$(this.north).setStyle({height:0});
+$(this.east).setStyle({width:0,height:0});
+$(this.south).setStyle({height:0});
+$(this.west).setStyle({width:0,height:0});
+$(this.imgWrap).setStyle({"width":this.imgW+"px","height":this.imgH+"px"});
+$(this.selArea).hide();
+var _1a={x1:0,y1:0,x2:0,y2:0};
+var _1b=false;
+if(this.options.onloadCoords!=null){
+_1a=this.cloneCoords(this.options.onloadCoords);
+_1b=true;
+}else{
+if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0){
+_1a.x1=Math.ceil((this.imgW-this.options.ratioDim.x)/2);
+_1a.y1=Math.ceil((this.imgH-this.options.ratioDim.y)/2);
+_1a.x2=_1a.x1+this.options.ratioDim.x;
+_1a.y2=_1a.y1+this.options.ratioDim.y;
+_1b=true;
+}
+}
+this.setAreaCoords(_1a,false,false,1);
+if(this.options.displayOnInit&&_1b){
+this.selArea.show();
+this.drawArea();
+this.endCrop();
+}
+this.attached=true;
+},remove:function(){
+if(this.attached){
+this.attached=false;
+this.imgWrap.parentNode.insertBefore(this.img,this.imgWrap);
+this.imgWrap.parentNode.removeChild(this.imgWrap);
+Event.stopObserving(this.dragArea,"mousedown",this.startDragBind);
+Event.stopObserving(document,"mousemove",this.onDragBind);
+Event.stopObserving(document,"mouseup",this.endCropBind);
+this.registerHandles(false);
+if(this.options.captureKeys){
+Event.stopObserving(document,"keypress",this.keysBind);
+}
+}
+},reset:function(){
+if(!this.attached){
+this.onLoad();
+}else{
+this.setParams();
+}
+this.endCrop();
+},handleKeys:function(e){
+var dir={x:0,y:0};
+if(!this.dragging){
+switch(e.keyCode){
+case (37):
+dir.x=-1;
+break;
+case (38):
+dir.y=-1;
+break;
+case (39):
+dir.x=1;
+break;
+case (40):
+dir.y=1;
+break;
+}
+if(dir.x!=0||dir.y!=0){
+if(e.shiftKey){
+dir.x*=10;
+dir.y*=10;
+}
+this.moveArea([this.areaCoords.x1+dir.x,this.areaCoords.y1+dir.y]);
+Event.stop(e);
+}
+}
+},calcW:function(){
+return (this.areaCoords.x2-this.areaCoords.x1);
+},calcH:function(){
+return (this.areaCoords.y2-this.areaCoords.y1);
+},moveArea:function(_1e){
+this.setAreaCoords({x1:_1e[0],y1:_1e[1],x2:_1e[0]+this.calcW(),y2:_1e[1]+this.calcH()},true,false);
+this.drawArea();
+},cloneCoords:function(_1f){
+return {x1:_1f.x1,y1:_1f.y1,x2:_1f.x2,y2:_1f.y2};
+},setAreaCoords:function(_20,_21,_22,_23,_24){
+if(_21){
+var _25=_20.x2-_20.x1;
+var _26=_20.y2-_20.y1;
+if(_20.x1<0){
+_20.x1=0;
+_20.x2=_25;
+}
+if(_20.y1<0){
+_20.y1=0;
+_20.y2=_26;
+}
+if(_20.x2>this.imgW){
+_20.x2=this.imgW;
+_20.x1=this.imgW-_25;
+}
+if(_20.y2>this.imgH){
+_20.y2=this.imgH;
+_20.y1=this.imgH-_26;
+}
+}else{
+if(_20.x1<0){
+_20.x1=0;
+}
+if(_20.y1<0){
+_20.y1=0;
+}
+if(_20.x2>this.imgW){
+_20.x2=this.imgW;
+}
+if(_20.y2>this.imgH){
+_20.y2=this.imgH;
+}
+if(_23!=null){
+if(this.ratioX>0){
+this.applyRatio(_20,{x:this.ratioX,y:this.ratioY},_23,_24);
+}else{
+if(_22){
+this.applyRatio(_20,{x:1,y:1},_23,_24);
+}
+}
+var _27=[this.options.minWidth,this.options.minHeight];
+var _28=[this.options.maxWidth,this.options.maxHeight];
+if(_27[0]>0||_27[1]>0||_28[0]>0||_28[1]>0){
+var _29={a1:_20.x1,a2:_20.x2};
+var _2a={a1:_20.y1,a2:_20.y2};
+var _2b={min:0,max:this.imgW};
+var _2c={min:0,max:this.imgH};
+if((_27[0]!=0||_27[1]!=0)&&_22){
+if(_27[0]>0){
+_27[1]=_27[0];
+}else{
+if(_27[1]>0){
+_27[0]=_27[1];
+}
+}
+}
+if((_28[0]!=0||_28[0]!=0)&&_22){
+if(_28[0]>0&&_28[0]<=_28[1]){
+_28[1]=_28[0];
+}else{
+if(_28[1]>0&&_28[1]<=_28[0]){
+_28[0]=_28[1];
+}
+}
+}
+if(_27[0]>0){
+this.applyDimRestriction(_29,_27[0],_23.x,_2b,"min");
+}
+if(_27[1]>1){
+this.applyDimRestriction(_2a,_27[1],_23.y,_2c,"min");
+}
+if(_28[0]>0){
+this.applyDimRestriction(_29,_28[0],_23.x,_2b,"max");
+}
+if(_28[1]>1){
+this.applyDimRestriction(_2a,_28[1],_23.y,_2c,"max");
+}
+_20={x1:_29.a1,y1:_2a.a1,x2:_29.a2,y2:_2a.a2};
+}
+}
+}
+this.areaCoords=_20;
+},applyDimRestriction:function(_2d,val,_2f,_30,_31){
+var _32;
+if(_31=="min"){
+_32=((_2d.a2-_2d.a1)<val);
+}else{
+_32=((_2d.a2-_2d.a1)>val);
+}
+if(_32){
+if(_2f==1){
+_2d.a2=_2d.a1+val;
+}else{
+_2d.a1=_2d.a2-val;
+}
+if(_2d.a1<_30.min){
+_2d.a1=_30.min;
+_2d.a2=val;
+}else{
+if(_2d.a2>_30.max){
+_2d.a1=_30.max-val;
+_2d.a2=_30.max;
+}
+}
+}
+},applyRatio:function(_33,_34,_35,_36){
+var _37;
+if(_36=="N"||_36=="S"){
+_37=this.applyRatioToAxis({a1:_33.y1,b1:_33.x1,a2:_33.y2,b2:_33.x2},{a:_34.y,b:_34.x},{a:_35.y,b:_35.x},{min:0,max:this.imgW});
+_33.x1=_37.b1;
+_33.y1=_37.a1;
+_33.x2=_37.b2;
+_33.y2=_37.a2;
+}else{
+_37=this.applyRatioToAxis({a1:_33.x1,b1:_33.y1,a2:_33.x2,b2:_33.y2},{a:_34.x,b:_34.y},{a:_35.x,b:_35.y},{min:0,max:this.imgH});
+_33.x1=_37.a1;
+_33.y1=_37.b1;
+_33.x2=_37.a2;
+_33.y2=_37.b2;
+}
+},applyRatioToAxis:function(_38,_39,_3a,_3b){
+var _3c=Object.extend(_38,{});
+var _3d=_3c.a2-_3c.a1;
+var _3e=Math.floor(_3d*_39.b/_39.a);
+var _3f;
+var _40;
+var _41=null;
+if(_3a.b==1){
+_3f=_3c.b1+_3e;
+if(_3f>_3b.max){
+_3f=_3b.max;
+_41=_3f-_3c.b1;
+}
+_3c.b2=_3f;
+}else{
+_3f=_3c.b2-_3e;
+if(_3f<_3b.min){
+_3f=_3b.min;
+_41=_3f+_3c.b2;
+}
+_3c.b1=_3f;
+}
+if(_41!=null){
+_40=Math.floor(_41*_39.a/_39.b);
+if(_3a.a==1){
+_3c.a2=_3c.a1+_40;
+}else{
+_3c.a1=_3c.a1=_3c.a2-_40;
+}
+}
+return _3c;
+},drawArea:function(){
+var _42=this.calcW();
+var _43=this.calcH();
+var px="px";
+var _45=[this.areaCoords.x1+px,this.areaCoords.y1+px,_42+px,_43+px,this.areaCoords.x2+px,this.areaCoords.y2+px,(this.img.width-this.areaCoords.x2)+px,(this.img.height-this.areaCoords.y2)+px];
+var _46=this.selArea.style;
+_46.left=_45[0];
+_46.top=_45[1];
+_46.width=_45[2];
+_46.height=_45[3];
+var _47=Math.ceil((_42-6)/2)+px;
+var _48=Math.ceil((_43-6)/2)+px;
+this.handleN.style.left=_47;
+this.handleE.style.top=_48;
+this.handleS.style.left=_47;
+this.handleW.style.top=_48;
+this.north.style.height=_45[1];
+var _49=this.east.style;
+_49.top=_45[1];
+_49.height=_45[3];
+_49.left=_45[4];
+_49.width=_45[6];
+var _4a=this.south.style;
+_4a.top=_45[5];
+_4a.height=_45[7];
+var _4b=this.west.style;
+_4b.top=_45[1];
+_4b.height=_45[3];
+_4b.width=_45[0];
+this.subDrawArea();
+this.forceReRender();
+},forceReRender:function(){
+if(this.isIE||this.isWebKit){
+var n=document.createTextNode(" ");
+var d,el,fixEL,i;
+if(this.isIE){
+fixEl=this.selArea;
+}else{
+if(this.isWebKit){
+fixEl=document.getElementsByClassName("imgCrop_marqueeSouth",this.imgWrap)[0];
+d=Builder.node("div","");
+d.style.visibility="hidden";
+var _4e=["SE","S","SW"];
+for(i=0;i<_4e.length;i++){
+el=document.getElementsByClassName("imgCrop_handle"+_4e[i],this.selArea)[0];
+if(el.childNodes.length){
+el.removeChild(el.childNodes[0]);
+}
+el.appendChild(d);
+}
+}
+}
+fixEl.appendChild(n);
+fixEl.removeChild(n);
+}
+},startResize:function(e){
+this.startCoords=this.cloneCoords(this.areaCoords);
+this.resizing=true;
+this.resizeHandle=Event.element(e).classNames().toString().replace(/([^N|NE|E|SE|S|SW|W|NW])+/,"");
+Event.stop(e);
+},startDrag:function(e){
+this.selArea.show();
+this.clickCoords=this.getCurPos(e);
+this.setAreaCoords({x1:this.clickCoords.x,y1:this.clickCoords.y,x2:this.clickCoords.x,y2:this.clickCoords.y},false,false,null);
+this.dragging=true;
+this.onDrag(e);
+Event.stop(e);
+},getCurPos:function(e){
+var el=this.imgWrap,wrapOffsets=Position.cumulativeOffset(el);
+while(el.nodeName!="BODY"){
+wrapOffsets[1]-=el.scrollTop||0;
+wrapOffsets[0]-=el.scrollLeft||0;
+el=el.parentNode;
+}
+return curPos={x:Event.pointerX(e)-wrapOffsets[0],y:Event.pointerY(e)-wrapOffsets[1]};
+},onDrag:function(e){
+if(this.dragging||this.resizing){
+var _54=null;
+var _55=this.getCurPos(e);
+var _56=this.cloneCoords(this.areaCoords);
+var _57={x:1,y:1};
+if(this.dragging){
+if(_55.x<this.clickCoords.x){
+_57.x=-1;
+}
+if(_55.y<this.clickCoords.y){
+_57.y=-1;
+}
+this.transformCoords(_55.x,this.clickCoords.x,_56,"x");
+this.transformCoords(_55.y,this.clickCoords.y,_56,"y");
+}else{
+if(this.resizing){
+_54=this.resizeHandle;
+if(_54.match(/E/)){
+this.transformCoords(_55.x,this.startCoords.x1,_56,"x");
+if(_55.x<this.startCoords.x1){
+_57.x=-1;
+}
+}else{
+if(_54.match(/W/)){
+this.transformCoords(_55.x,this.startCoords.x2,_56,"x");
+if(_55.x<this.startCoords.x2){
+_57.x=-1;
+}
+}
+}
+if(_54.match(/N/)){
+this.transformCoords(_55.y,this.startCoords.y2,_56,"y");
+if(_55.y<this.startCoords.y2){
+_57.y=-1;
+}
+}else{
+if(_54.match(/S/)){
+this.transformCoords(_55.y,this.startCoords.y1,_56,"y");
+if(_55.y<this.startCoords.y1){
+_57.y=-1;
+}
+}
+}
+}
+}
+this.setAreaCoords(_56,false,e.shiftKey,_57,_54);
+this.drawArea();
+Event.stop(e);
+}
+},transformCoords:function(_58,_59,_5a,_5b){
+var _5c=[_58,_59];
+if(_58>_59){
+_5c.reverse();
+}
+_5a[_5b+"1"]=_5c[0];
+_5a[_5b+"2"]=_5c[1];
+},endCrop:function(){
+this.dragging=false;
+this.resizing=false;
+this.options.onEndCrop(this.areaCoords,{width:this.calcW(),height:this.calcH()});
+},subInitialize:function(){
+},subDrawArea:function(){
+}};
+Cropper.ImgWithPreview=Class.create();
+Object.extend(Object.extend(Cropper.ImgWithPreview.prototype,Cropper.Img.prototype),{subInitialize:function(){
+this.hasPreviewImg=false;
+if(typeof (this.options.previewWrap)!="undefined"&&this.options.minWidth>0&&this.options.minHeight>0){
+this.previewWrap=$(this.options.previewWrap);
+this.previewImg=this.img.cloneNode(false);
+this.previewImg.id="imgCrop_"+this.previewImg.id;
+this.options.displayOnInit=true;
+this.hasPreviewImg=true;
+this.previewWrap.addClassName("imgCrop_previewWrap");
+this.previewWrap.setStyle({width:this.options.minWidth+"px",height:this.options.minHeight+"px"});
+this.previewWrap.appendChild(this.previewImg);
+}
+},subDrawArea:function(){
+if(this.hasPreviewImg){
+var _5d=this.calcW();
+var _5e=this.calcH();
+var _5f={x:this.imgW/_5d,y:this.imgH/_5e};
+var _60={x:_5d/this.options.minWidth,y:_5e/this.options.minHeight};
+var _61={w:Math.ceil(this.options.minWidth*_5f.x)+"px",h:Math.ceil(this.options.minHeight*_5f.y)+"px",x:"-"+Math.ceil(this.areaCoords.x1/_60.x)+"px",y:"-"+Math.ceil(this.areaCoords.y1/_60.y)+"px"};
+var _62=this.previewImg.style;
+_62.width=_61.w;
+_62.height=_61.h;
+_62.left=_61.x;
+_62.top=_61.y;
+}
+}});
+
--- /dev/null
+// InPlaceEditor extension based somewhat on an example given in the
+// scriptaculous wiki
+Ajax.InPlaceEditor.prototype.__initialize = Ajax.InPlaceEditor.prototype.initialize;
+Ajax.InPlaceEditor.prototype.__getText = Ajax.InPlaceEditor.prototype.getText;
+Object.extend(Ajax.InPlaceEditor.prototype, {
+ initialize: function(element, url, options) {
+ this.__initialize(element, url, options);
+ this.setOptions(options);
+ // Remove this line to stop from auto-showing the
+ // empty caption text on page load.
+ this.checkEmpty();
+ },
+
+ setOptions: function(options) {
+ this.options = Object.extend(Object.extend(this.options, {
+ emptyClassName: 'inplaceeditor-empty'
+ }),options||{});
+ },
+
+ checkEmpty: function() {
+ if (this.element.innerHTML.length == 0) {
+ emptyNode = new Element('span', {className: this.options.emptyClassName}).update(this.options.emptyText);
+ this.element.appendChild(emptyNode);
+ }
+ },
+
+ getText: function() {
+ $(this.element).select('.' + this.options.emptyClassName).each(function(child) {
+ this.element.removeChild(child);
+ }.bind(this));
+ return this.__getText();
+ }
+});
+
+function tileExit(ipe, e)
+{
+ ipe.checkEmpty();
+}
--- /dev/null
+document.observe('dom:loaded', function() {
+ Ansel.deleteFace = function(image_id, face_id)
+ {
+ new Ajax.Request(Ansel.ajax.editFaces.url,
+ {
+ method: 'post',
+ parameters: {
+ action: 'delete',
+ image: image_id,
+ face: face_id
+ }
+ });
+ $('face' + face_id).remove();
+ };
+
+ Ansel.setFaceName = function(image_id, face_id)
+ {
+ new Ajax.Request(Ansel.ajax.editFaces.url,
+ {
+ method: 'post',
+ parameters:
+ {
+ action: 'setname',
+ face: face_id,
+ image: image_id,
+ facename: encodeURIComponent($F('facename' + face_id))
+ },
+ onComplete: function(r) {
+ if (r.responseJSON.response == 1) {
+ $('faces_widget_content').update(r.responseJSON.message);
+ }
+ }
+ }
+ );
+ };
+
+ Ansel.doFaceEdit = function(image_id)
+ {
+ $('faces_widget_content').update(Ansel.ajax.editFaces.text.loading);
+ new Ajax.Request(Ansel.ajax.editFaces.url,
+ {
+ method: 'post',
+ parameters:
+ {
+ action: 'process',
+ image: image_id
+ },
+ onComplete: function(r) {
+ if (r.responseJSON.response == 1) {
+ $('faces_widget_content').update(r.responseJSON.message);
+ }
+ }
+ }
+ );
+ };
+});
\ No newline at end of file
--- /dev/null
+//<![CDATA[
+Event.observe(window, 'load', function() {
+ // The number of unique, embedded instances
+ var nodeCount = anselnodes.length;
+
+ // Holds any lightbox json
+ var lightboxData = new Array();
+
+ // Iterate over each embedded instance and create the DOM elements.
+ for (var n = 0; n < nodeCount; n++) {
+
+ // j is the textual name of the container, used as a key
+ var j = anselnodes[n];
+
+ // Do we have any lightbox data?
+ if (typeof anseljson[j]['lightbox'] != 'undefined') {
+ lightboxData = lightboxData.concat(anseljson[j]['lightbox']);
+ }
+
+ // Top level DOM node for this embedded instannce
+ var mainNode = $(j);
+
+ // Used if we have requested the optional paging feature
+ if (anseljson[j]['perpage']) {
+ var pagecount = anseljson[j]['perpage'];
+ } else {
+ var pagecount = anseljson[j]['data'].size();
+ }
+
+ // For each image in this instance, create the DOM structure
+ for (var i = 0; i < pagecount; i++) {
+ // Need a nested function and closures to force new scope
+ (function() {
+ var jx = j;
+ var ix = i;
+ var imgContainer = new Element('span', {className: 'anselGalleryWidget'});
+ if (!anseljson[jx]['hideLinks']) {
+ if (anseljson[jx]['linkToGallery']) {
+ var idx = 6;
+ } else {
+ var idx = 5;
+ }
+ var imgLink = imgContainer.appendChild(new Element('a',
+ {
+ href: anseljson[jx]['data'][ix][idx],
+ title: anseljson[jx]['data'][ix][2]
+ }));
+ var lb_data = {image: anseljson[jx]['data'][ix][3]};
+ imgLink.appendChild(new Element('img', {src: anseljson[jx]['data'][ix][0]}));
+ // Attach the lightbox action if we have lightbox data
+ if (typeof anseljson[j]['lightbox'] != 'undefined') {
+ imgLink.observe('click', function(e) {ansel_lb.start(lb_data.image); e.stop();});
+ }
+ } else {
+ imgContainer.appendChild(new Element('img', {src: anseljson[jx]['data'][ix][0]}));
+ // Attach the lightbox action if we have lightbox data
+ if (typeof anseljson[j]['lightbox'] != 'undefined') {
+ imgLink.observe('click', function(e) {ansel_lb.start(lb_data.image); e.stop();});
+ }
+ }
+
+ mainNode.appendChild(imgContainer);
+ })();
+ }
+
+ if (anseljson[j]['perpage'] > 0) {
+ (function() {
+ var jx = j;
+
+ var nextLink = new Element('a',{href: '#', title: 'Next Image', className: 'anselNext', style: 'text-decoration:none;width:40%;float:right;'});
+ nextLink.update('>>');
+ var arg1 = {node: jx, page: 1};
+ nextLink.observe('click', function(e) {displayPage(e, arg1)});
+
+ var prevLink = new Element('a',{href: '#', title: 'Previous Image', className: 'anselPrev', style: 'text-decoration:none;width:40%;float:right;'});
+ prevLink.update('<<');
+ var arg2 = {node: jx, page: -1};
+ prevLink.observe('click', function(e) {displayPage(e, arg2)});
+ $(jx).appendChild(nextLink);
+ $(jx).appendChild(prevLink);
+ Horde_ToolTips.attachBehavior(jx);
+ Event.observe(window, 'unload', Horde_ToolTips.out.bind(Horde_ToolTips));
+
+ })();
+ } else {
+ (function () {
+ var jx = j;
+ Horde_ToolTips.attachBehavior(jx);
+ })();
+ }
+ }
+ if (lightboxData.length) {
+ lbOptions['gallery_json'] = lightboxData;
+ ansel_lb = new Lightbox(lbOptions);
+ }
+
+ Event.observe(window, 'unload', Horde_ToolTips.out.bind(Horde_ToolTips));
+ });
+
+/**
+ * Display the images from the requested page for the requested node.
+ *
+ * @param string $node The DOM id of the embedded widget.
+ * @param integer $page The requested page number.
+ */
+function displayPage(event, args) {
+ var node = args.node;
+ var page = args.page;
+ var perpage = anseljson[node]['perpage'];
+ var imgcount = anseljson[node]['data'].size();
+ var pages = Math.ceil(imgcount / perpage) - 1;
+ var oldPage = anseljson[node]['page'];
+
+ page = oldPage + page;
+
+ /* Rollover? */
+ if (page > pages) {
+ page = 0;
+ }
+ if (page < 0) {
+ page = pages;
+ }
+
+ var mainNode = $(node);
+ mainNode.update();
+ var start = page * perpage;
+ var end = Math.min(imgcount - 1, start + perpage - 1);
+ for (var i = start; i <= end; i++) {
+ var imgContainer = mainNode.appendChild(new Element('span', {className: 'anselGalleryWidget'}));
+ var imgLink = imgContainer.appendChild(new Element('a',
+ {
+ href: anseljson[node]['data'][i][5],
+ alt: anseljson[node]['data'][i][2],
+ title: anseljson[node]['data'][i][2]
+ }));
+ imgLink.appendChild(new Element('img', {src: anseljson[node]['data'][i][0]}));
+ }
+
+ var nextLink = new Element('a',{href: '', title: 'Next Image', style: 'text-decoration:none;width:40%;float:right;'});
+ nextLink.update('>>');
+
+ var args = {node: node, page: ++oldPage};
+ nextLink.observe('click', function(e) {displayPage(e, args);}.bind());
+
+ var prevLink = new Element('a',{href: '', title: 'Previous Image', style: 'text-decoration:none;width:40%;float:right;'});
+ prevLink.update('<<');
+
+ var args = {node: node, page: --oldPage};
+ prevLink.observe('click', function(e) {displayPage(e, args);}.bind());
+
+ mainNode.appendChild(nextLink);
+ mainNode.appendChild(prevLink);
+
+ Horde_ToolTips.attachBehavior(node);
+ anseljson[node]['page'] = page;
+ event.stop();
+}
+//]
--- /dev/null
+/**
+ * Google maps implementation for Ansel
+ *
+ * Copyright 2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ */
+var Ansel_GMap = Class.create();
+
+Ansel_GMap.prototype = {
+ // Main google map handle
+ mainMap: undefined,
+
+ // Smaller overview map handle
+ smallMap: undefined,
+
+ // Tinymarker icons...
+ tI: undefined,
+ tIO: undefined,
+
+ // GLatLngBounds obejct for calculating proper center and zoom
+ bounds: undefined,
+
+ // Geocoder
+ geocoder: undefined,
+
+ // MarkerManager, if we are browsing the map.
+ // Note we need <script src="http://gmaps-utility-library.googlecode.com/svn/trunk/markermanager/release/src/markermanager.js">
+ manager: undefined,
+
+ // Can override via options array
+ // Pass these in options array as empty string if you do not have them
+ // on your view
+ tilePrefix: 'imagetile_',
+ locationId: 'ansel_locationtext',
+ coordId: 'ansel_latlng',
+ relocateId: 'ansel_relocate',
+ deleteId: 'ansel_deleteGeotag',
+ maxZoom: 15,
+ defaultZoom: 15,
+ options: {},
+
+ // Array of GOverlays (GMarker or Ansel_GOverlay objects)
+ points: [],
+
+ // const'r
+ // options.smallMap = [id: 80px];
+ // .mainMap [id: xx]
+ // .viewType (Gallery, Image, Edit)
+ // .relocateUrl base url to the edit/relocate page
+ // .relocateText localized text for the relocate link
+ // .deleteGeotagText localized text for delete geotag link
+ // .deleteGeotagCallback js callback function to be called after
+ // deletion is successful
+
+ // .clickHandler - optional callback to handle click events on the mainMap
+ // .hasEdit - Has PERMS_EDIT on the image
+ // .calculateMaxZoom - call Google's getMaxZoomAtLatLng() method to
+ // avoid autozooming in to a level with no detail.
+ // Performance penalty because we make another
+ // round trip to google's service and lately it
+ // appears rather slow.
+ // .updateEndpoint URL to imple.php
+ initialize: function(options) {
+ // Use the manager by default.
+ if (typeof options.useManager == 'undefined') {
+ options.useManager = true;
+ }
+ this.mainMap = new GMap2($(options.mainMap));
+ this.mainMap.setMapType(G_HYBRID_MAP);
+ this.mainMap.setUIToDefault();
+ this.bounds = new GLatLngBounds();
+ this.geocoder = new GClientGeocoder();
+ this.options = options;
+ if (options.tilePrefix) {
+ this.tilePrefix = options.tilePrefix;
+ }
+
+ if (typeof options.calculateMaxZoom == 'undefined') {
+ options.calculateMaxZoom = true;
+ }
+
+ if (options.smallMap) {
+ this.smallMap = new GMap2($(options.smallMap));
+ var cUI = this.smallMap.getDefaultUI();
+ cUI.controls.menumaptypecontrol = false;
+ this.smallMap.setUI(cUI);
+
+ // Create our "tiny" marker icon
+ // We should copy these locally once this is fleshed out...
+ this.tI = new GIcon();
+ this.tI.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
+ this.tI.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
+ this.tI.iconSize = new GSize(12, 20);
+ this.tI.shadowSize = new GSize(22, 20);
+ this.tI.iconAnchor = new GPoint(6, 20);
+ this.tI.infoWindowAnchor = new GPoint(5, 1);
+ this.tIO = { icon:this.tI };
+ }
+
+ // Clean up
+ document.observe('unload', function() {GUnload();});
+ },
+
+ /**
+ * Adds a set of points to the map. Each entry in the points array should
+ * contain:
+ * image_latitude,image_longitude
+ * (optional)markerOnly - Don't add thumbnails or event handlers
+ *
+ * @param array
+ * @param minZoom at what minimum zoom level should this set of points be
+ * displayed? Ignored if not using the MarkerManager
+ */
+ addPoints: function(points, minZoom) {
+ var l = points.length;
+ for (var i = 0; i < l; i++) {
+ var ll = new GLatLng(parseFloat(points[i].image_latitude), parseFloat(points[i].image_longitude));
+ this.bounds.extend(ll);
+ if (points[i].markerOnly == true) {
+ // We only support draggable GMarkers, not custom overlays.
+ if (points[i].draggable) {
+ var mO = {draggable: true};
+ var marker = new GMarker(ll, mO);
+ GEvent.addListener(marker, "drag", function(ll) {
+ $(this.coordId).update(this._point2Deg(ll));
+ }.bind(this));
+ GEvent.addListener(marker, "dragend", function(ll) {
+ this.geocoder.getLocations(ll, function(address) {
+ this.getLocationCallback(address, new GMarker(ll));
+ }.bind(this));
+ }.bind(this));
+ } else {
+ // This is the single marker for the current image in the image view.
+ // Make sure we have a high enough zIndex value for it.
+ var marker = new GMarker(ll, {zIndexProcess: function(marker) {return GOverlay.getZIndex(-90);}});
+ }
+ } else {
+ var marker = new anselGOverlay(ll, points[i]);
+ }
+ // Click handlers only apply to our custom GOverlay.
+ if (!points[i].markerOnly && !options.viewType == 'Block') {
+ (function() {
+ var p = points[i];
+ GEvent.addDomListener(marker.div_, 'click', function() {
+ a = $$('#' + this.tilePrefix + p.image_id + ' a')[0];
+ if (!a.onclick || a.onclick() != false) {
+ location.href = a.href;
+ }
+ }.bind(this));}.bind(this))();
+ }
+ // extend the GOverlay with our image data too.
+ marker.image_data = points[i];
+ this.points.push(marker);
+
+ // Only put the current image on the small map if we are in the
+ // Image view.
+ if (this.options.smallMap &&
+ (options.viewType != 'Image' || points[i].markerOnly)) {
+ var marker2 = new GMarker(ll, this.tIO);
+ this.smallMap.addOverlay(marker2);
+ }
+ }
+
+ if (this.options.viewType == 'Gallery' || this.options.viewType == 'Block') {
+ if (this.options.calculateMaxZoom) {
+ this.mainMap.getCurrentMapType().getMaxZoomAtLatLng(this.bounds.getCenter(), function(response) {
+ if (response.status != 200) {
+ var zl = Math.min(this.mainMap.getBoundsZoomLevel(this.bounds) - 1, this.maxZoom);
+ } else {
+ var zl = Math.min(this.mainMap.getBoundsZoomLevel(this.bounds) - 1, Math.min(this.maxZoom, response.zoom - 1));
+ }
+ this._mapSetCenter(zl);
+ this._managerSetup(minZoom);
+ }.bind(this));
+ } else {
+ this._mapSetCenter(Math.min(this.mainMap.getBoundsZoomLevel(this.bounds) - 1, this.maxZoom));
+ this._managerSetup(minZoom);
+ }
+ } else {
+ // Not a Gallery View...
+ this.mainMap.setCenter(this.points[0].getLatLng(), Math.min(this.mainMap.getBoundsZoomLevel(this.bounds) - 1, this.maxZoom));
+ // Can't instantiate a manager until after the GMap2 has had
+ // setCenter() called, so we can't do this in the const'r
+ if (this.options.useManager && this.manager == null) {
+ this.manager = new MarkerManager(this.mainMap);
+ }
+ if (this.options.useManager) {
+ if (minZoom == null) {
+ minZoom = 0;
+ }
+ this.manager.addMarkers(this.points, minZoom);
+ this.manager.refresh();
+ }
+ if (this.options.smallMap) {
+ this.smallMap.setCenter(this.mainMap.getCenter(), 1);
+ }
+ }
+ },
+
+ /**
+ * Helper method to set the map center and refresh the MarkerManager
+ * if we are using one.
+ *
+ * @param integer zl The zoom level to set the map at once it's centered.
+ * @param integer mz The minimum zoom level needed to display the currently
+ * added points if using the MarkerManager.
+ */
+ _mapSetCenter: function(zl, mz) {
+ this.mainMap.setCenter(this.bounds.getCenter(), zl);
+ if (this.options.smallMap) {
+ this.smallMap.setCenter(this.mainMap.getCenter(), 1);
+ }
+ },
+
+ _managerSetup: function(mz) {
+ // Can't instantiate a manager until after the GMap2 has had
+ // setCenter() called, so we *must* do this here.
+ if (this.options.useManager && this.manager == null) {
+ this.manager = new MarkerManager(this.mainMap);
+ }
+ if (this.options.useManager) {
+ if (mz == null) {
+ mz = 0;
+ }
+ this.manager.addMarkers(this.points, mz);
+ this.manager.refresh();
+ }
+ },
+
+ /**
+ * Display all points on the map. If we are using the MarkerManager, then
+ * this function only obtains the reverse geocode data and (via the callback)
+ * adds the event handlers to display the geocode data. If we aren't using
+ * the manager, this also adds the overlay to the map.
+ */
+ display: function() {
+ var l = this.points.length;
+ for (var i = 0; i < l; i++) {
+ // Force closure on p
+ (function() {
+ var p = this.points[i];
+ if (!this.options.useManager) {
+ this.mainMap.addOverlay(p);
+ }
+ // For now, only do this on the current Image in the image view
+ // or for all images in Gallery view.
+ if ((this.options.viewType != 'Block' && this.options.viewType != 'Image') || p.image_data.markerOnly) {
+ this.getLocations(p);
+ }
+ }.bind(this))();
+ }
+
+ if (this.options.clickHandler) {
+ GEvent.addListener(this.mainMap, "click", this.options.clickHandler);
+ }
+ },
+
+ /**
+ * Custom getLocations method so we can check for our own locally cached
+ * geodata first. We can't implement our own GGeocodeCache becuase we want
+ * to allow a per-user override of an individual image, not a general cache
+ * of lat/lng => location text.
+ */
+ getLocations: function(p) {
+ if (p.image_data.image_location.length > 0) {
+ r = {Status: {code: 200}, Placemark: [{AddressDetails: {Accuracy: 4}, address:p.image_data.image_location}], NoUpdate: true};
+ this.getLocationCallback(r, p, false);
+ } else {
+ this.geocoder.getLocations(p.getLatLng(), function(address) {this.getLocationCallback(address, p, true)}.bind(this));
+ }
+ },
+
+ /**
+ * Callback to parse and attach location data the the points on the map.
+ * Adds event handlers to display the location data on mouseover. Also
+ * highlights the image tile (since these would only be called in gallery
+ * view) - need to use a seperate handler for that once we start storing
+ * reverse geocode data locally.
+ *
+ * @TODO: Is it worth the effort to define the callback in the page that
+ * is calling this to make this more OO-like? Maybe for H4 when I
+ * try to make this a more generic Google library??
+ *
+ */
+ getLocationCallback: function(points, marker, update) {
+ if (typeof update == 'undefined') { update = false;}
+ if (points.Status.code != 200) {
+ // Fake the data so we can at least update what we have
+ points.Placemark = [{AddressDetails: {Accuracy: 0}, address: ''}];
+ update = false;
+ }
+
+ if (marker.image_data) {
+ var image_data = marker.image_data;
+ } else {
+ image_data = {};
+ }
+
+ for (var i = 0; i < points.Placemark.length; i++) {
+ var place = points.Placemark[i];
+ if (place.AddressDetails.Accuracy <= 4) {
+ // These events handlers should only be fired on the Gallery
+ // view for our special GOverlay objects (which already have
+ // a mouseover/out handler to focus them).
+ if (!image_data.markerOnly && this.options.viewType == 'Gallery' && this.locationId) {
+ GEvent.addDomListener(marker.div_, 'mouseover', function() {
+ $(this.locationId).update(place.address);
+ $$('#' + this.tilePrefix + image_data.image_id + ' img')[0].toggleClassName('image-tile-highlight');
+ }.bind(this));
+ GEvent.addDomListener(marker.div_, 'mouseout', function() {
+ $(this.locationId).update('<br />');
+ $$('#' + this.tilePrefix + image_data.image_id + ' img')[0].toggleClassName('image-tile-highlight');
+ }.bind(this));
+ }
+
+ // Cache the location locally?
+ if (update) {
+ new Ajax.Request(this.options['updateEndpoint'],
+ {
+ method: 'post',
+ parameters: {
+ type: 'location',
+ location: encodeURIComponent(place.address),
+ img: image_data.image_id
+ }
+ }
+ );
+ }
+ // These handlers are for the image tiles themselves in the
+ // Gallery view - to highlight our GOverlays on the map.
+ if (this.options.viewType == 'Gallery') {
+ if (this.locationId) {
+ $$('#' + this.tilePrefix + image_data.image_id + ' img')[0].observe('mouseover', function() {
+ $(this.locationId).update(place.address);
+ $$('#' + this.tilePrefix + image_data.image_id + ' img')[0].toggleClassName('image-tile-highlight');
+ marker.focus();
+ }.bind(this));
+ $$('#' + this.tilePrefix + image_data.image_id + ' img')[0].observe('mouseout', function() {
+ $(this.locationId).update('<br />');
+ $$('#' + this.tilePrefix + image_data.image_id + ' img')[0].toggleClassName('image-tile-highlight');
+ marker.div_.style.border = '1px solid white';
+ marker.focus();
+ }.bind(this));
+ }
+
+ return;
+ } else if (this.options.viewType == 'Image') {
+ // If Image view and this is the markerOnly point.
+ if (image_data.markerOnly) {
+ if (this.locationId) {
+ $(this.locationId).update(place.address);
+ }
+ if (this.coordId) {
+ $(this.coordId).update(this._point2Deg(marker.getLatLng()));
+ }
+ if (this.relocateId) {
+ $(this.relocateId).update(this._getRelocateLink(image_data.image_id));
+ }
+
+ if (this.deleteId) {
+ $(this.deleteId).update(this._getDeleteLink(image_data.image_id));
+ }
+ }
+
+ return;
+ } else {
+ // Edit view
+ $(this.locationId).update(place.address);
+ $(this.coordId).update(this._point2Deg(marker.getLatLng()));
+
+ return;
+ }
+
+ } else {
+ // Parse less detail, or just move on to the next hit??
+ }
+ }
+ },
+
+ _point2Deg: function(ll) {
+ function dec2deg(dec, lat)
+ {
+ var letter = lat ? (dec > 0 ? "N" : "S") : (dec > 0 ? "E" : "W");
+ dec = Math.abs(dec);
+ var deg = Math.floor(dec);
+ var min = Math.floor((dec - deg) * 60);
+ var sec = (dec - deg - min / 60) * 3600;
+ return deg + "° " + min + "' " + sec.toFixed(2) + "\" " + letter;
+ }
+
+ return dec2deg(ll.lat(), true) + " " + dec2deg(ll.lng());
+ },
+
+ _getRelocateLink: function(iid) {
+ if (options.hasEdit) {
+ var a = new Element('a', {href: this.options.relocateUrl + '?image=' + iid}).update(this.options.relocateText);
+ a.observe('click', function(e) { Horde.popup({ url: this.options.relocateUrl, params: 'image=' + iid, width: 750, height: 600 }); e.stop();}.bind(this));
+ return a;
+ } else {
+ return '';
+ }
+ },
+
+ _getDeleteLink: function(iid) {
+ var x = new Element('a', {href: this.options.relocateUrl + '?image=' + iid}).update(this.options.deleteGeotagText);
+ x.observe('click', function(e) {this.options.deleteGeotagCallback(); e.stop();}.bindAsEventListener(this));
+ return x;
+ }
+
+}
+
+/**
+ * Define our custom GOverlay to display thumbnails of images on the map.
+ * Use an Image object to get the exact dimensions of the image. Need this
+ * wrapped in an onload handler to be sure GOverlay() is defined.
+ */
+anselGOverlay = function(latlng, image_data) {
+ this.src_ = image_data.icon;
+ this.latlng_ = latlng;
+ var img = new Image();
+ img.src = image_data.icon;
+ this.width_ = img.width;
+ this.height_ = img.height;
+ var z = GOverlay.getZIndex(this.latlng_.lat());
+ this.div_ = new Element('div', {style: 'position:absolute;border:1px solid white;width:' + (this.width_ - 2) + 'px; height:' + (this.height_ - 2) + 'px;zIndex:' + z});
+ this.img_ = new Element('img', {src: this.src_, style: 'width:' + (this.width_ - 2) + 'px;height:' + (this.height_ - 2) + 'px'});
+ this.div_.appendChild(this.img_);
+ this.selected_ = false;
+ this.link = image_data.link;
+
+ // Handlers to hightlight the node for this overlay on mouseover/out
+ GEvent.addDomListener(this.div_, 'mouseover', function() {
+ this.focus();
+ }.bind(this));
+ GEvent.addDomListener(this.div_, 'mouseout', function() {
+ this.focus();
+ }.bind(this));
+
+ // Add a click handler to navigate to the image view for this image.
+ if (this.link) {
+ GEvent.addDomListener(this.div_, 'click', function() {
+ var a = this.link;
+ location.href = a;
+ }.bind(this));
+ }
+ };
+
+ anselGOverlay.prototype = new GOverlay();
+ anselGOverlay.prototype.initialize = function(map) {
+ map.getPane(G_MAP_MARKER_PANE).appendChild(this.div_);
+ this.map_ = map;
+ };
+
+ //Remove the main DIV from the map pane
+ // TODO: We should unregister the event handlers adding in initialize()
+ anselGOverlay.prototype.remove = function() {
+ this.div_.parentNode.removeChild(this.div_);
+ };
+
+ // Copy our data to a new GOverlay
+ anselGOverlay.prototype.copy = function() {
+ return new Ansel_GOverlay(this.latlng_, this.src_);
+ };
+
+ anselGOverlay.prototype.redraw = function(force) {
+ // We only need to redraw if the coordinate system has changed
+ if (!force) return;
+ var coords = this.map_.fromLatLngToDivPixel(this.latlng_);
+ this.div_.style.left = coords.x + "px";
+ this.div_.style.top = coords.y + "px";
+};
+
+anselGOverlay.prototype.focus = function()
+{
+ if (this.selected_ == false) {
+ this.div_.style.border = '1px solid red';
+ this.div_.style.left = (parseInt(this.div_.style.left) - 1) + "px";
+ this.div_.style.top = (parseInt(this.div_.style.top) - 1) + "px";
+ this.div_.style.zIndex = GOverlay.getZIndex(-90.0);
+ this.selected_ = true;
+ } else {
+ this.div_.style.border = '1px solid white';
+ this.div_.style.left = (parseInt(this.div_.style.left) + 1) + "px";
+ this.div_.style.top = (parseInt(this.div_.style.top) + 1) + "px";
+ this.div_.style.zIndex = GOverlay.getZIndex(this.latlng_.lat());
+ this.selected_ = false;
+ }
+};
+
+// MarkerManager seems to be incosistent with the methods it calls to get
+// the GLatLng for each overlay. addMarkers() seems to need the deprecated
+// getPoint() while addMarker() uses the newer getLatLng() mehtod.
+anselGOverlay.prototype.getPoint = function() {
+ return this.latlng_;
+}
+anselGOverlay.prototype.getLatLng = function() {
+ return this.latlng_;
+}
--- /dev/null
+/**
+ * Javascript specific for the adding/moving a geotag via the map_edit.php page
+ *
+ * Copyright 2009 The Horde Project (http://www.horde.org)
+ *
+ * @author Michael J. Rubinsky
+ * @package Ansel
+ */
+
+/**
+ * Ansel_MapEdit class encapsulates various functions for searching/setting
+ * locations.
+ *
+ * mapEdit = new Ansel_MapEdit(options)
+ *
+ * options is an object with the following required properties:
+ *
+ * mainMap - DOM id for the google map
+ * image_id - The image_id for the Ansel_Image we are tagging.
+ * gettext - Various gettext strings (fetching, errortext)
+ * xurl - The URL for imple.php
+ *
+ * and some optional properties:
+ *
+ * statusId - DOM id for a status message
+ * locationInput - DOM id for the location search input field
+ * locationAction - DOM id for the Find button
+ * isNew - Set to 1 if image is a newly geotagged image, 0 if we are
+ * moving an existing geotag.
+ *
+ *
+ */
+Ansel_MapEdit = Class.create();
+Ansel_MapEdit.prototype = {
+
+ _options: null,
+ _map: null,
+
+ // {image_latitude: image_longitude:}
+ ll: null,
+
+ initialize: function(options)
+ {
+ this._options = Object.extend({
+ statusId: 'status',
+ locationInput: 'locationInput',
+ locationAction: 'locationAction',
+ isNew: '0'
+ }, options);
+
+ this._map = new Ansel_GMap({mainMap: this._options.mainMap,
+ viewType: 'Edit',
+ useManager: false,
+ clickHandler: function(ol, ll, olll) {
+ this._map.points[0].setLatLng(ll);
+ this._map.points[0].image_data = {image_location: '',
+ image_latitude: ll.lat(),
+ image_longitude: ll.lng()};
+ this._map.getLocations(this._map.points[0]);
+ }.bind(this)});
+ if (this._options.isNew) {
+ this._map.maxZoom = 1;
+ }
+
+ this._map._getLocationCallback = this._map.getLocationCallback;
+ this._map.getLocationCallback = function(points, marker) {
+ this._map._getLocationCallback(points, marker);
+ }.bind(this);
+
+ this._map.addPoints(this._options.points);
+ this._map.display();
+ $(this._options.locationAction).observe('click', function(e) {this.getLocation();e.stop();}.bindAsEventListener(this));
+ $(this._options.saveId).observe('click', function() {this.handleSave(this._options.image_id);}.bind(this));
+ },
+
+ handleSave: function(id)
+ {
+ var o = this._options;
+ params = {
+ img: id,
+ lat: this._map.points[0].getLatLng().lat(),
+ lng: this._map.points[0].getLatLng().lng(),
+ type: 'geotag'
+ };
+ //url = this._options.url;
+ new Ajax.Request(o.xurl, {
+ method: 'post',
+ parameters: params,
+ onComplete: function(transport) {
+ if (transport.responseJSON.response > 0) {
+ window.opener.location.href = window.opener.location.href;
+ window.close();
+ } // what to do if failure?
+ }
+ });
+ },
+
+ getLocation: function()
+ {
+ var o = this._options;
+
+ $(this._options.statusId).update(this._options.gettext.fetching);
+ if (this.ll) {
+ //already have lat/lng from the autocompleter
+ var gll = new GLatLng(this.ll.image_latitude, this.ll.image_longitude);
+ this._map.points[0].setLatLng(gll);
+ this._map.points[0].image_data = {image_location: $F(o.locationInput),
+ image_latitude: gll.lat(),
+ image_longitude: gll.lng()};
+
+ this._map.getLocations(this._map.points[0]);
+ this._map.mainMap.setCenter(gll, this._map.defaultZoom);
+ $(o.statusId).update('');
+ } else {
+ this._map.geocoder.getLocations($(o.locationInput).value, function(address) {
+ if (address.Status.code == '200') {
+ // For now, just try the first returned spot - not sure how else to handle this
+ var lat = address.Placemark[0].Point.coordinates[1];
+ var lng = address.Placemark[0].Point.coordinates[0];
+ var gll = new GLatLng(lat, lng);
+ this._map.points[0].setLatLng(gll);
+ this._map.points[0].image_data = {image_location: '',
+ image_latitude: lat,
+ image_longitude: lng};
+
+ this._map.getLocations(this._map.points[0]);
+ this._map.mainMap.setCenter(gll, this._map.defaultZoom);
+ $(o.statusId).update('');
+ } else {
+ $(o.statusId).update(o.gettext.errortext + address.Status.code);
+ }
+ }.bind(this));
+ }
+ },
+
+ setLocation: function(lat, lng, loc)
+ {
+ var gll = new GLatLng(lat, lng);
+ this._map.points[0].setLatLng(gll);
+ this._map.points[0].image_data = {image_location: loc,
+ image_latitude: lat,
+ image_longitude: lng};
+
+ this._map.getLocations(this._map.points[0]);
+ this._map.mainMap.setCenter(gll, this._map.defaultZoom);
+ }
+
+}
+
+/**
+ * Override the Ajax.Autocompleter#updateChoices method so we can handle
+ * receiving lat/lng points bound to the location.
+ */
+Ajax.Autocompleter.prototype.updateChoices = function(choices) {
+ var li, re, ul,
+ i = 0;
+ this.geocache = choices;
+ var hc = $H(choices);
+ if (!this.changed && this.hasFocus) {
+ li = new Element('LI');
+ ul = new Element('UL');
+ re = new RegExp("(" + this.getToken() + ")", "i");
+ var k = hc.keys();
+ k.each(function(n) {
+ ul.insert(li.cloneNode(false).writeAttribute('acIndex', i++).update(n.gsub(re, '<strong>#{1}</strong>')));
+ });
+
+ this.update.update(ul);
+
+ this.entryCount = k.size();
+ ul.childElements().each(this.addObservers.bind(this));
+
+ this.stopIndicator();
+ this.index = 0;
+
+ if (this.entryCount == 1 && this.options.autoSelect) {
+ this.selectEntry();
+ } else {
+ this.render();
+ }
+ }
+
+ if (this.options.afterUpdateChoices) {
+ this.options.afterUpdateChoices(hc, ul);
+ }
+}
+
+/**
+ * Override the Autocompler.Local#initialize method to take an Object instead
+ * of an Array, and set the appropriate properties.
+ */
+Autocompleter.Local.prototype.initialize = function(element, update, obj, options) {
+ this.baseInitialize(element, update, options);
+ this.geocache = obj;
+ this.options.arr = $H(obj).keys();
+}
--- /dev/null
+function showFace(id)
+{
+ $('facediv' + id).addClassName('shown');
+ $('facethumb' + id).style.border = '1px solid red';
+ $('facedivname' + id).style.display = 'inline';
+}
+function hideFace(id)
+{
+ $('facediv' + id).removeClassName('shown');
+ $('facethumb' + id).style.border = '1px solid black';
+ $('facedivname' + id).style.display = 'none';
+}
+document.observe('dom:loaded', function() {
+ Event.observe($('photodiv'), 'load', function() {
+ $('faces-on-image').immediateDescendants().collect(function(element) {
+ element.clonePosition($('photodiv'), {setWidth: false, setHeight: false});
+ });
+ });
+});
--- /dev/null
+// This file modified in various ways for use in Ansel. Mostly to allow
+// the lightbox images to span multiple gallery pages...and thus is no longer
+// really "Lightbox", but a good bit of the original code is still intact.
+// The original credits/copyright appears below.
+
+// -----------------------------------------------------------------------------------
+//
+// Lightbox v2.04
+// by Lokesh Dhakar - http://www.lokeshdhakar.com
+// Last Modification: 2/9/08
+//
+// For more information, visit:
+// http://lokeshdhakar.com/projects/lightbox2/
+//
+// Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
+// - Free for use in both personal and commercial projects
+// - Attribution requires leaving author name, author link, and the license info intact.
+//
+// Thanks: Scott Upton(uptonic.com), Peter-Paul Koch(quirksmode.com), and Thomas Fuchs(mir.aculo.us) for ideas, libs, and snippets.
+// Artemy Tregubenko (arty.name) for cleanup and help in updating to latest ver of proto-aculous.
+//
+// -----------------------------------------------------------------------------------
+/*
+
+ Table of Contents
+ -----------------
+ Configuration
+
+ Lightbox Class Declaration
+ - initialize()
+ - updateImageList()
+ - start()
+ - changeImage()
+ - resizeImageContainer()
+ - showImage()
+ - updateDetails()
+ - updateNav()
+ - enableKeyboardNav()
+ - disableKeyboardNav()
+ - keyboardAction()
+ - preloadNeighborImages()
+ - end()
+
+ Function Calls
+ - document.observe()
+
+*/
+// -----------------------------------------------------------------------------------
+
+var Lightbox = Class.create();
+
+Lightbox.prototype = {
+ imageArray: [],
+ activeImage: undefined,
+ options: undefined,
+
+ // initialize()
+ // Constructor runs on completion of the DOM loading. Calls updateImageList and then
+ // the function inserts html at the bottom of the page which is used to display the shadow
+ // overlay and the image container.
+ //
+ // Modified 3/25/2008 Michael J. Rubinsky <mrubinsk@horde.org> to remove
+ // dependency on scriptaculous' Builder object since the new Element
+ // constructor in Prototype does this more efficently.
+ initialize: function(options) {
+
+ this.options = options;
+ this.imageArray = this.options.gallery_json;
+ this.keyboardAction = this.keyboardAction.bindAsEventListener(this);
+ if (this.options.resizeSpeed > 10) this.options.resizeSpeed = 10;
+ if (this.options.resizeSpeed < 1) this.options.resizeSpeed = 1;
+ this.resizeDuration = this.options.animate ? ((11 - this.options.resizeSpeed) * 0.15) : 0;
+ this.overlayDuration = this.options.animate ? 0.2 : 0; // shadow fade in/out duration
+
+ // When Lightbox starts it will resize itself from 250 by 250 to the current image dimension.
+ // If animations are turned off, it will be hidden as to prevent a flicker of a
+ // white 250 by 250 box.
+
+ var size = (this.options.animate ? 250 : 1) + 'px';
+
+ // Code inserts html at the bottom of the page that looks similar to this:
+ //
+ // <div id="overlay"></div>
+ // <div id="lightbox">
+ // <div id="outerImageContainer">
+ // <div id="imageContainer">
+ // <img id="lightboxImage">
+ // <div style="" id="hoverNav">
+ // <a href="#" id="prevLink"></a>
+ // <a href="#" id="nextLink"></a>
+ // </div>
+ // <div id="loading">
+ // <a href="#" id="loadingLink">
+ // <img src="images/loading.gif">
+ // </a>
+ // </div>
+ // </div>
+ // </div>
+ // <div id="imageDataContainer">
+ // <div id="imageData">
+ // <div id="imageDetails">
+ // <span id="caption"></span>
+ // <span id="numberDisplay"></span>
+ // </div>
+ // <div id="bottomNav">
+ // <a href="#" id="bottomNavClose">
+ // <img src="images/close.gif">
+ // </a>
+ // </div>
+ // </div>
+ // </div>
+ // </div>
+
+
+ var objBody = $$('body')[0];
+
+ objBody.appendChild(new Element('div', {id: 'overlay'}));
+
+ // Build innermost children
+ var hoverNav = new Element('div', {id: 'hoverNav'});
+ hoverNav.appendChild(new Element('a', {id:'prevLink', href: '#'}));
+ hoverNav.appendChild(new Element('a', {id: 'nextLink', href: '#'}));
+
+ var loadingLink = new Element('a', {id: 'loadingLink', href: '#'});
+ loadingLink.appendChild(new Element('img', {src: this.options.fileLoadingImage}));
+
+ var loading = new Element('div', {id: 'loading'});
+ loading.appendChild(loadingLink);
+
+ var container = new Element('div', {id: 'imageContainer'});
+ container.appendChild(new Element('img', {id: 'lightboxImage'}));
+ container.appendChild(hoverNav);
+ container.appendChild(loading);
+
+ var outerContainer = new Element('div', {id: 'outerImageContainer'});
+ outerContainer.appendChild(container);
+
+ var imageDetails = new Element('div', {id: 'imageDetails'});
+ imageDetails.appendChild(new Element('span', {id: 'caption'}));
+ imageDetails.appendChild(new Element('span', {id: 'numberDisplay'}));
+
+ var bottomClose = new Element('a', {id: 'bottomNavClose', href: '#'});
+ bottomClose.appendChild(new Element('img', {src: this.options.fileBottomNavCloseImage}));
+
+ var bottomNav = new Element('div', {id: 'bottomNav'});
+ bottomNav.appendChild(bottomClose);
+
+ var imageData = new Element('div', {id: 'imageData'});
+ imageData.appendChild(imageDetails);
+ imageData.appendChild(bottomNav);
+
+ var imageDataContainer = new Element('div', {id: 'imageDataContainer'});
+ imageDataContainer.appendChild(imageData);
+
+ // The outermost node
+ var lightbox = new Element('div', {id: 'lightbox'});
+ lightbox.appendChild(outerContainer);
+ lightbox.appendChild(imageDataContainer);
+
+ objBody.appendChild(lightbox);
+
+ $('overlay').hide().observe('click', (function() { this.end(); }).bind(this));
+ $('lightbox').hide().observe('click', (function(event) { if (event.element().id == 'lightbox') this.end(); }).bind(this));
+ $('outerImageContainer').setStyle({ width: size, height: size });
+
+ // Need to cache the event listener function so we can call stopObserving() later
+ this.prevEventListener = (function(event) { event.stop(); this.changeImage(this.activeImage - 1); }).bindAsEventListener(this);
+ $('prevLink').observe('click', this.prevEventListener);
+
+ this.nextEventListener = (function(event) { event.stop(); this.changeImage(this.activeImage + 1); }).bindAsEventListener(this);
+ $('nextLink').observe('click', this.nextEventListener);
+ $('loadingLink').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
+ $('bottomNavClose').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
+ },
+
+ //
+ // start()
+ // Display overlay and lightbox.
+ //
+ start: function(imageId) {
+
+ $$('select', 'object', 'embed').invoke('setStyle', 'visibility:hidden');
+
+ // stretch overlay to fill page and fade in
+ var arrayPageSize = this.getPageSize();
+ $('overlay').setStyle({ height: arrayPageSize[1] + 'px' });
+
+ new Effect.Appear($('overlay'), { duration: this.overlayDuration, from: 0.0, to: this.options.overlayOpacity });
+
+ // calculate top and left offset for the lightbox
+ var arrayPageScroll = document.viewport.getScrollOffsets();
+ var lightboxTop = arrayPageScroll[1] + (document.viewport.getHeight() / 15);
+ var lightboxLeft = arrayPageScroll[0];
+ $('lightbox').setStyle({ top: lightboxTop + 'px', left: lightboxLeft + 'px' }).show();
+
+ // Need to find the index for this image.
+ var imageNum = 0;
+ while (this.imageArray[imageNum][3] != imageId || imageNum > this.imageArray.length - 1) {
+ imageNum++;
+ }
+
+ this.changeImage(imageNum);
+ return false;
+ },
+
+ //
+ // changeImage()
+ // Hide most elements and preload image in preparation for resizing image container.
+ //
+ changeImage: function(imageNum) {
+ this.activeImage = imageNum; // update global var
+
+ // hide elements during transition
+ if (this.options.animate) $('loading').show();
+ $('lightboxImage', 'hoverNav', 'prevLink', 'nextLink', 'numberDisplay').invoke('hide');
+ // HACK: Opera9 does not currently support scriptaculous opacity and appear fx
+ $('imageDataContainer').setStyle({opacity: .0001});
+
+ var imgPreloader = new Image();
+
+ // once image is preloaded, resize image container
+ imgPreloader.onload = (function(){
+ $('lightboxImage').src = this.imageArray[this.activeImage][0];
+ this.resizeImageContainer(imgPreloader.width, imgPreloader.height);
+ }).bind(this);
+ imgPreloader.src = this.imageArray[this.activeImage][0];
+ },
+
+ //
+ // resizeImageContainer()
+ //
+ resizeImageContainer: function(imgWidth, imgHeight) {
+
+ // get current width and height
+ var widthCurrent = $('outerImageContainer').getWidth();
+ var heightCurrent = $('outerImageContainer').getHeight();
+
+ // get new width and height
+ var widthNew = (imgWidth + this.options.borderSize * 2);
+ var heightNew = (imgHeight + this.options.borderSize * 2);
+
+ // scalars based on change from old to new
+ var xScale = (widthNew / widthCurrent) * 100;
+ var yScale = (heightNew / heightCurrent) * 100;
+
+ // calculate size difference between new and old image, and resize if necessary
+ var wDiff = widthCurrent - widthNew;
+ var hDiff = heightCurrent - heightNew;
+
+ if (hDiff != 0) new Effect.Scale($('outerImageContainer'), yScale, {scaleX: false, duration: this.resizeDuration, queue: 'front'});
+ if (wDiff != 0) new Effect.Scale($('outerImageContainer'), xScale, {scaleY: false, duration: this.resizeDuration, delay: this.resizeDuration});
+
+ // if new and old image are same size and no scaling transition is necessary,
+ // do a quick pause to prevent image flicker.
+ var timeout = 0;
+ if ((hDiff == 0) && (wDiff == 0)){
+ timeout = 100;
+ if (Prototype.Browser.IE) timeout = 250;
+ }
+
+ (function(){
+ $('prevLink', 'nextLink').invoke('setStyle', 'height:' + imgHeight + 'px');
+ $('imageDataContainer').setStyle({ width: widthNew + 'px' });
+ this.showImage();
+ }).bind(this).delay(timeout / 1000);
+ },
+
+ //
+ // showImage()
+ // Display image and begin preloading neighbors.
+ //
+ showImage: function(){
+ $('loading').hide();
+ new Effect.Appear($('lightboxImage'), {
+ duration: this.resizeDuration,
+ queue: 'end',
+ afterFinish: (function(){ this.updateDetails(); }).bind(this)
+ });
+ this.preloadNeighborImages();
+ },
+
+ //
+ // updateDetails()
+ // Display caption, image number, and bottom nav.
+ //
+ updateDetails: function() {
+
+ // use caption, or fall back to the file name if it's empty.
+ if (this.imageArray[this.activeImage][2] != ""){
+ $('caption').update(this.imageArray[this.activeImage][2]).show();
+ } else {
+ $('caption').update(this.imageArray[this.activeImage][1]).show();
+ }
+
+ // if image is part of set display 'Image x of x'
+ if (this.imageArray.length > 1){
+ $('numberDisplay').update( this.options.labelImage + ' ' + (this.activeImage + 1) + ' ' + this.options.labelOf + ' ' + this.imageArray.length).show();
+ }
+
+ new Effect.Parallel(
+ [
+ new Effect.SlideDown($('imageDataContainer'), { sync: true, duration: this.resizeDuration, from: 0.0, to: 1.0 }),
+ new Effect.Appear($('imageDataContainer'), { sync: true, duration: this.resizeDuration })
+ ],
+ {
+ duration: this.resizeDuration,
+ afterFinish: (function() {
+ // update overlay size and update nav
+ var arrayPageSize = this.getPageSize();
+ $('overlay').setStyle({ height: arrayPageSize[1] + 'px' });
+ this.updateNav();
+ }).bind(this)
+ }
+ );
+ },
+
+ //
+ // updateNav()
+ // Display appropriate previous and next hover navigation.
+ //
+ updateNav: function() {
+
+ $('hoverNav').show();
+ // if not first image in set, display prev image button
+ if (this.activeImage > 0) $('prevLink').show();
+
+ // if not last image in set, display next image button
+ if (this.activeImage < (this.imageArray.length - 1)) $('nextLink').show();
+
+ this.enableKeyboardNav();
+ },
+
+ //
+ // enableKeyboardNav()
+ //
+ enableKeyboardNav: function() {
+ document.observe('keydown', this.keyboardAction);
+ },
+
+ //
+ // disableKeyboardNav()
+ //
+ disableKeyboardNav: function() {
+ document.stopObserving('keydown', this.keyboardAction);
+ },
+
+ //
+ // keyboardAction()
+ //
+ keyboardAction: function(event) {
+ var keycode = event.keyCode;
+
+ var escapeKey;
+ if (event.DOM_VK_ESCAPE) { // mozilla
+ escapeKey = event.DOM_VK_ESCAPE;
+ } else { // ie
+ escapeKey = 27;
+ }
+
+ var key = String.fromCharCode(keycode).toLowerCase();
+
+ if (key.match(/x|o|c/) || (keycode == escapeKey)){ // close lightbox
+ this.end();
+ } else if ((key == 'p') || (keycode == 37)){ // display previous image
+ if (this.activeImage != 0){
+ this.disableKeyboardNav();
+ this.changeImage(this.activeImage - 1);
+ }
+ } else if ((key == 'n') || (keycode == 39)){ // display next image
+ if (this.activeImage != (this.imageArray.length - 1)){
+ this.disableKeyboardNav();
+ this.changeImage(this.activeImage + 1);
+ }
+ }
+ },
+
+ //
+ // preloadNeighborImages()
+ // Preload previous and next images.
+ //
+ preloadNeighborImages: function(){
+ var preloadNextImage, preloadPrevImage;
+ if (this.imageArray.length > this.activeImage + 1){
+ preloadNextImage = new Image();
+ preloadNextImage.src = this.imageArray[this.activeImage + 1][0];
+ }
+ if (this.activeImage > 0){
+ preloadPrevImage = new Image();
+ preloadPrevImage.src = this.imageArray[this.activeImage - 1][0];
+ }
+
+ },
+
+ //
+ // end()
+ //
+ end: function() {
+ this.disableKeyboardNav();
+ $('lightbox').hide();
+ new Effect.Fade($('overlay'), { duration: this.overlayDuration });
+ $$('select', 'object', 'embed').invoke('setStyle', 'visibility:visible');
+
+ //redirect here//
+ if (this.options.startPage != this.imageArray[this.activeImage][4]) {
+ location.href = this.options.returnURL + "page=" + this.imageArray[this.activeImage][4];
+ }
+ },
+
+ //
+ // getPageSize()
+ //
+ getPageSize: function() {
+
+ var xScroll, yScroll;
+
+ if (window.innerHeight && window.scrollMaxY) {
+ xScroll = window.innerWidth + window.scrollMaxX;
+ yScroll = window.innerHeight + window.scrollMaxY;
+ } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
+ xScroll = document.body.scrollWidth;
+ yScroll = document.body.scrollHeight;
+ } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
+ xScroll = document.body.offsetWidth;
+ yScroll = document.body.offsetHeight;
+ }
+
+ var windowWidth, windowHeight;
+
+ if (self.innerHeight) { // all except Explorer
+ if(document.documentElement.clientWidth){
+ windowWidth = document.documentElement.clientWidth;
+ } else {
+ windowWidth = self.innerWidth;
+ }
+ windowHeight = self.innerHeight;
+ } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
+ windowWidth = document.documentElement.clientWidth;
+ windowHeight = document.documentElement.clientHeight;
+ } else if (document.body) { // other Explorers
+ windowWidth = document.body.clientWidth;
+ windowHeight = document.body.clientHeight;
+ }
+
+ // for small pages with total height less then height of the viewport
+ if(yScroll < windowHeight){
+ pageHeight = windowHeight;
+ } else {
+ pageHeight = yScroll;
+ }
+
+ // for small pages with total width less then width of the viewport
+ if(xScroll < windowWidth){
+ pageWidth = xScroll;
+ } else {
+ pageWidth = windowWidth;
+ }
+
+ return [pageWidth,pageHeight];
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ * You can only have one SlideController on a page.
+ */
+var SlideController = {
+
+ photos: null,
+ photoId: 0,
+
+ slide: null,
+
+ interval: null,
+ intervalSeconds: 5,
+
+ /**
+ * CSS border size x 2
+ */
+ borderSize: 0,
+
+ /**
+ * So we can update the links
+ */
+ baseUrl: null,
+ galleryId: 0,
+ galleryShare: 0,
+ playing: false,
+ interval: null,
+ tempImage: new Image(),
+
+ /**
+ * Initialization.
+ */
+ initialize: function(photos, start, baseUrl, galleryId, galleryShare) {
+ SlideController.photoId = start || 0;
+ SlideController.baseUrl = baseUrl;
+ SlideController.galleryId = galleryId;
+ SlideController.galleryShare = galleryShare;
+
+ Event.observe(window, 'load', function() {
+ Event.observe(SlideController.tempImage, 'load', function() {
+ SlideController.photo.initSwap();
+ });
+ Event.observe($('Photo'), 'load', function() {
+ SlideController.photo.showPhoto();
+ });
+
+ SlideController.photos = photos;
+ SlideController.photo = new Slide(SlideController.photoId);
+ SlideController.photo.initSwap();
+ SlideController.play();
+
+ });
+ },
+
+ /**
+ */
+ play: function() {
+ Element.hide('ssPlay');
+ Element.show('ssPause');
+ // This sets the first interval for the currently displayed image.
+ if (SlideController.interval) {
+ clearTimeout(SlideController.interval);
+ }
+ SlideController.interval = setTimeout(SlideController.next, SlideController.intervalSeconds * 1000);
+ SlideController.playing = true;
+ },
+
+ /**
+ */
+ pause: function() {
+ Element.hide('ssPause');
+ Element.show('ssPlay');
+ if (SlideController.interval) {
+ clearTimeout(SlideController.interval);
+ }
+ SlideController.playing = false;
+ },
+
+ /**
+ */
+ prev: function() {
+ SlideController.photo.prevPhoto();
+ },
+
+ /**
+ */
+ next: function() {
+ SlideController.photo.nextPhoto();
+ }
+
+}
+
+// -----------------------------------------------------------------------------------
+//
+// This page coded by Scott Upton
+// http://www.uptonic.com | http://www.couloir.org
+//
+// This work is licensed under a Creative Commons License
+// Attribution-ShareAlike 2.0
+// http://creativecommons.org/licenses/by-sa/2.0/
+//
+// Associated APIs copyright their respective owners
+//
+// -----------------------------------------------------------------------------------
+// --- version date: 11/28/05 --------------------------------------------------------
+//
+// Various changes for properly updating image links, image comments etc...
+// added 4/07 by Michael Rubinsky <mrubinsk@horde.org>
+
+/**
+ * Additional methods for Element added by SU, Couloir.
+ */
+Object.extend(Element, {
+ getWidth: function(element) {
+ element = $(element);
+ return element.offsetWidth;
+ },
+ setWidth: function(element,w) {
+ element = $(element);
+ element.style.width = w + 'px';
+ },
+ setSrc: function(element,src) {
+ element = $(element);
+ element.src = src;
+ },
+ setHref: function(element,href) {
+ element = $(element);
+ element.href = href;
+ },
+ setInnerHTML: function(element,content) {
+ element = $(element);
+ element.innerHTML = content;
+ },
+ setOnClick: function(element,action) {
+ element = $(element);
+ element.onclick = action;
+ }
+});
+
+var Slide = Class.create();
+Slide.prototype = {
+ initialize: function(photoId) {
+ this.photoId = photoId;
+ this.photo = 'Photo';
+ this.captionBox = 'CaptionContainer';
+ this.caption = 'Caption';
+ },
+ setNewPhotoParams: function() {
+ // Set source of new image.
+ Element.setSrc(this.photo, SlideController.photos[SlideController.photoId][0]);
+
+ // Add caption from gallery array.
+ Element.setInnerHTML(this.caption, SlideController.photos[SlideController.photoId][2]);
+
+ try {
+ document.title = document.title.replace(SlideController.photos[this.photoId][1],
+ SlideController.photos[SlideController.photoId][1]);
+ if (parent.frames.horde_main) {
+ parent.document.title = document.title;
+ }
+ } catch (e) {}
+ },
+ updateLinks: function() {
+
+ var params = '?gallery=' + SlideController.galleryId + '&image=' + SlideController.photos[SlideController.photoId][3] + '&page=' + SlideController.photos[SlideController.photoId][4];
+
+ Element.setInnerHTML('PhotoName', SlideController.photos[SlideController.photoId][1]);
+ Element.setInnerHTML('breadcrumb_image', SlideController.photos[SlideController.photoId][1]);
+ Element.setHref($('breadcrumb_image'), SlideController.baseUrl + '/view.php' + params + '&view=Image');
+ Element.setHref($('breadcrumb_gallery'), SlideController.baseUrl + '/view.php' + params + '&view=Gallery');
+ if ($('image_properties_link')) {
+ Element.setHref('image_properties_link', SlideController.baseUrl + '/image.php' + params + '&actionID=modify&share=' + SlideController.galleryShare);
+ Element.setOnClick('image_properties_link', function(){SlideController.pause();Horde.popup({ url: this.href });return false;});
+ }
+ if ($('image_edit_link')) {
+ Element.setHref('image_edit_link', SlideController.baseUrl + '/image.php' + params + '&actionID=editimage');
+ }
+ if ($('image_ecard_link')) {
+ Element.setHref('image_ecard_link', SlideController.baseUrl + '/img/ecard.php?image=' + SlideController.photos[SlideController.photoId][3] + '&gallery=' + SlideController.galleryId);
+ Element.setOnClick('image_ecard_link', function(){SlideController.pause();Horde.popup({ url: this.href });return false;});
+ }
+ if ($('image_delete_link')) {
+ //TODO : Guess we should have PHP save the localized text for this...
+ var deleteAction = function() {return window.confirm("Do you want to permanently delete " + SlideController.photos[SlideController.photoId][1])};
+ Element.setHref($("image_delete_link"), SlideController.baseUrl + '/image.php' + params + '&actionID=delete');
+ Element.setOnClick('image_delete_link', deleteAction);
+ }
+ Element.setHref('image_download_link', SlideController.baseUrl + '/img/download.php?image=' + SlideController.photos[SlideController.photoId][3]);
+ Element.setOnClick('image_download_link', function(){SlideController.pause();});
+ },
+
+ showPhoto: function() {
+ new Effect.Appear(this.photo, { duration: 1.0, queue: 'end', afterFinish: (function() { Element.show(this.captionBox); this.updateLinks();}).bind(this) });
+
+ if (SlideController.playing) {
+ if (SlideController.interval) {
+ clearTimeout(SlideController.interval);
+ }
+ SlideController.interval = setTimeout(SlideController.next, SlideController.intervalSeconds * 1000);
+ }
+ },
+ nextPhoto: function() {
+ // Figure out which photo is next.
+ (SlideController.photoId == (SlideController.photos.length - 1)) ? SlideController.photoId = 0 : ++SlideController.photoId;
+ // Make sure the photo is loaded locally before we fade the current image.
+ SlideController.tempImage.src = SlideController.photos[SlideController.photoId][0];
+
+ },
+ prevPhoto: function() {
+ // Figure out which photo is previous.
+ (SlideController.photoId == 0) ? SlideController.photoId = SlideController.photos.length - 1 : --SlideController.photoId;
+ SlideController.tempImage.src = SlideController.photos[SlideController.photoId][0];
+ },
+ initSwap: function() {
+ // Begin by hiding main elements.
+ new Effect.Fade(this.captionBox, {duration: 0.5 });
+ new Effect.Fade(this.photo, { duration: 1.0, afterFinish: (function() { SlideController.photo.setNewPhotoParams();})});
+
+ // Update the current photo id.
+ this.photoId = SlideController.photoId;
+ }
+}
+ // Arrow keys for navigation
+ document.observe('keydown', arrowHandler);
+function arrowHandler(e)
+{
+ if (e.altKey || e.shiftKey || e.ctrlKey) {
+ return;
+ }
+
+ switch (e.keyCode || e.charCode) {
+ case Event.KEY_LEFT:
+ SlideController.prev();
+ break;
+
+ case Event.KEY_RIGHT:
+ SlideController.next();
+ break;
+ }
+}
--- /dev/null
+function checkSlug()
+{
+ slug = document.gallery.gallery_slug.value;
+ // Empty slugs are always allowed.
+ if (!slug.length) {
+ return true;
+ }
+
+ if (slug != Ansel.ajax.gallerySlugCheck.slugText) {
+ var url = Ansel.ajax.gallerySlugCheck.url;
+ var params = new Object();
+ params.slug = slug;
+ new Ajax.Request(url, {
+ method: 'post',
+ parameters: params,
+ onComplete: function(transport) {
+ var slugFlag = $('slug_flag');
+ response = transport.responseJSON.response;
+ if (response == 1) {
+ if (slugFlag.hasClassName('problem')) {
+ slugFlag.removeClassName('problem');
+ }
+ slugFlag.addClassName('success');
+ $('gallery_submit').enable();
+ // In case we try various slugs
+ Ansel.ajax.gallerySlugCheck.slugText = slug;
+ } else {
+ if (slugFlag.hasClassName('success')) {
+ slugFlag.removeClassName('success');
+ }
+ slugFlag.addClassName('problem');
+ $('gallery_submit').disable();
+ }
+ }
+ });
+ } else {
+ if (slugFlag.hasClassName('problem')) {
+ slugFlag.removeClassName('problem');
+ }
+ slugFlag.addClassName('success');
+ $('gallery_submit').enable();
+ }
+}
+++ /dev/null
-
-var Builder={NODEMAP:{AREA:'map',CAPTION:'table',COL:'table',COLGROUP:'table',LEGEND:'fieldset',OPTGROUP:'select',OPTION:'select',PARAM:'object',TBODY:'table',TD:'table',TFOOT:'table',TH:'table',THEAD:'table',TR:'table'},node:function(elementName){elementName=elementName.toUpperCase();var parentTag=this.NODEMAP[elementName]||'div';var parentElement=document.createElement(parentTag);try{parentElement.innerHTML="<"+elementName+"></"+elementName+">";}catch(e){}
-var element=parentElement.firstChild||null;if(element&&(element.tagName.toUpperCase()!=elementName))
-element=element.getElementsByTagName(elementName)[0];if(!element)element=document.createElement(elementName);if(!element)return;if(arguments[1])
-if(this._isStringOrNumber(arguments[1])||(arguments[1]instanceof Array)||arguments[1].tagName){this._children(element,arguments[1]);}else{var attrs=this._attributes(arguments[1]);if(attrs.length){try{parentElement.innerHTML="<"+elementName+" "+
-attrs+"></"+elementName+">";}catch(e){}
-element=parentElement.firstChild||null;if(!element){element=document.createElement(elementName);for(attr in arguments[1])
-element[attr=='class'?'className':attr]=arguments[1][attr];}
-if(element.tagName.toUpperCase()!=elementName)
-element=parentElement.getElementsByTagName(elementName)[0];}}
-if(arguments[2])
-this._children(element,arguments[2]);return element;},_text:function(text){return document.createTextNode(text);},ATTR_MAP:{'className':'class','htmlFor':'for'},_attributes:function(attributes){var attrs=[];for(attribute in attributes)
-attrs.push((attribute in this.ATTR_MAP?this.ATTR_MAP[attribute]:attribute)+'="'+attributes[attribute].toString().escapeHTML().gsub(/"/,'"')+'"');return attrs.join(" ");},_children:function(element,children){if(children.tagName){element.appendChild(children);return;}
-if(typeof children=='object'){children.flatten().each(function(e){if(typeof e=='object')
-element.appendChild(e)
-else
-if(Builder._isStringOrNumber(e))
-element.appendChild(Builder._text(e));});}else
-if(Builder._isStringOrNumber(children))
-element.appendChild(Builder._text(children));},_isStringOrNumber:function(param){return(typeof param=='string'||typeof param=='number');},build:function(html){var element=this.node('div');$(element).update(html.strip());return element.down();},dump:function(scope){if(typeof scope!='object'&&typeof scope!='function')scope=window;var tags=("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY "+"BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET "+"FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+"KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+"PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+"TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);tags.each(function(tag){scope[tag]=function(){return Builder.node.apply(Builder,[tag].concat($A(arguments)));}});}}
\ No newline at end of file
+++ /dev/null
-/* Prototype-UI, version trunk
- *
- * Prototype-UI is freely distributable under the terms of an MIT-style license.
- * For details, see the PrototypeUI web site: http://www.prototype-ui.com/
- *
- *--------------------------------------------------------------------------*/
-
-if(typeof Prototype == 'undefined' || !Prototype.Version.match("1.6"))
- throw("Prototype-UI library require Prototype library >= 1.6.0");
-
-if (Prototype.Browser.WebKit) {
- Prototype.Browser.WebKitVersion = parseFloat(navigator.userAgent.match(/AppleWebKit\/([\d\.\+]*)/)[1]);
- Prototype.Browser.Safari2 = (Prototype.Browser.WebKitVersion < 420);
-}
-
-if (Prototype.Browser.IE) {
- Prototype.Browser.IEVersion = parseFloat(navigator.appVersion.split(';')[1].strip().split(' ')[1]);
- Prototype.Browser.IE6 = Prototype.Browser.IEVersion == 6;
- Prototype.Browser.IE7 = Prototype.Browser.IEVersion == 7;
-}
-
-Prototype.falseFunction = function() { return false };
-Prototype.trueFunction = function() { return true };
-
-/*
-Namespace: UI
-
- Introduction:
- Prototype-UI is a library of user interface components based on the Prototype framework.
- Its aim is to easilly improve user experience in web applications.
-
- It also provides utilities to help developers.
-
- Guideline:
- - Prototype conventions are followed
- - Everything should be unobstrusive
- - All components are themable with CSS stylesheets, various themes are provided
-
- Warning:
- Prototype-UI is still under deep development, this release is targeted to developers only.
- All interfaces are subjects to changes, suggestions are welcome.
-
- DO NOT use it in production for now.
-
- Authors:
- - Sébastien Gruhier, <http://www.xilinus.com>
- - Samuel Lebeau, <http://gotfresh.info>
-*/
-
-var UI = {
- Abstract: { },
- Ajax: { }
-};
-Object.extend(Class.Methods, {
- extend: Object.extend.methodize(),
-
- addMethods: Class.Methods.addMethods.wrap(function(proceed, source) {
- // ensure we are not trying to add null or undefined
- if (!source) return this;
-
- // no callback, vanilla way
- if (!source.hasOwnProperty('methodsAdded'))
- return proceed(source);
-
- var callback = source.methodsAdded;
- delete source.methodsAdded;
- proceed(source);
- callback.call(source, this);
- source.methodsAdded = callback;
-
- return this;
- }),
-
- addMethod: function(name, lambda) {
- var methods = {};
- methods[name] = lambda;
- return this.addMethods(methods);
- },
-
- method: function(name) {
- return this.prototype[name].valueOf();
- },
-
- classMethod: function() {
- $A(arguments).flatten().each(function(method) {
- this[method] = (function() {
- return this[method].apply(this, arguments);
- }).bind(this.prototype);
- }, this);
- return this;
- },
-
- // prevent any call to this method
- undefMethod: function(name) {
- this.prototype[name] = undefined;
- return this;
- },
-
- // remove the class' own implementation of this method
- removeMethod: function(name) {
- delete this.prototype[name];
- return this;
- },
-
- aliasMethod: function(newName, name) {
- this.prototype[newName] = this.prototype[name];
- return this;
- },
-
- aliasMethodChain: function(target, feature) {
- feature = feature.camelcase();
-
- this.aliasMethod(target+"Without"+feature, target);
- this.aliasMethod(target, target+"With"+feature);
-
- return this;
- }
-});
-Object.extend(Number.prototype, {
- // Snap a number to a grid
- snap: function(round) {
- return parseInt(round == 1 ? this : (this / round).floor() * round);
- }
-});
-/*
-Interface: String
-
-*/
-
-Object.extend(String.prototype, {
- camelcase: function() {
- var string = this.dasherize().camelize();
- return string.charAt(0).toUpperCase() + string.slice(1);
- },
-
- /*
- Method: makeElement
- toElement is unfortunately already taken :/
-
- Transforms html string into an extended element or null (when failed)
-
- > '<li><a href="#">some text</a></li>'.makeElement(); // => LI href#
- > '<img src="foo" id="bar" /><img src="bar" id="bar" />'.makeElement(); // => IMG#foo (first one)
-
- Returns:
- Extended element
-
- */
- makeElement: function() {
- var wrapper = new Element('div'); wrapper.innerHTML = this;
- return wrapper.down();
- }
-});
-Object.extend(Array.prototype, {
- empty: function() {
- return !this.length;
- },
-
- extractOptions: function() {
- return this.last().constructor === Object ? this.pop() : { };
- },
-
- removeAt: function(index) {
- var object = this[index];
- this.splice(index, 1);
- return object;
- },
-
- remove: function(object) {
- var index;
- while ((index = this.indexOf(object)) != -1)
- this.removeAt(index);
- return object;
- },
-
- insert: function(index) {
- var args = $A(arguments);
- args.shift();
- this.splice.apply(this, [ index, 0 ].concat(args));
- return this;
- }
-});
-Element.addMethods({
- getScrollDimensions: function(element) {
- return {
- width: element.scrollWidth,
- height: element.scrollHeight
- }
- },
-
- getScrollOffset: function(element) {
- return Element._returnOffset(element.scrollLeft, element.scrollTop);
- },
-
- setScrollOffset: function(element, offset) {
- element = $(element);
- if (arguments.length == 3)
- offset = { left: offset, top: arguments[2] };
- element.scrollLeft = offset.left;
- element.scrollTop = offset.top;
- return element;
- },
-
- // returns "clean" numerical style (without "px") or null if style can not be resolved
- // or is not numeric
- getNumStyle: function(element, style) {
- var value = parseFloat($(element).getStyle(style));
- return isNaN(value) ? null : value;
- },
-
- // by Tobie Langel (http://tobielangel.com/2007/5/22/prototype-quick-tip)
- appendText: function(element, text) {
- element = $(element);
- text = String.interpret(text);
- element.appendChild(document.createTextNode(text));
- return element;
- }
-});
-
-document.whenReady = function(callback) {
- if (document.loaded)
- callback.call(document);
- else
- document.observe('dom:loaded', callback);
-};
-
-Object.extend(document.viewport, {
- // Alias this method for consistency
- getScrollOffset: document.viewport.getScrollOffsets,
-
- setScrollOffset: function(offset) {
- Element.setScrollOffset(Prototype.Browser.WebKit ? document.body : document.documentElement, offset);
- },
-
- getScrollDimensions: function() {
- return Element.getScrollDimensions(Prototype.Browser.WebKit ? document.body : document.documentElement);
- }
-});
-/*
-Interface: UI.Options
- Mixin to handle *options* argument in initializer pattern.
-
- TODO: find a better example than Circle that use an imaginary Point function,
- this example should be used in tests too.
-
- It assumes class defines a property called *options*, containing
- default options values.
-
- Instances hold their own *options* property after a first call to <setOptions>.
-
- Example:
- > var Circle = Class.create(UI.Options, {
- >
- > // default options
- > options: {
- > radius: 1,
- > origin: Point(0, 0)
- > },
- >
- > // common usage is to call setOptions in initializer
- > initialize: function(options) {
- > this.setOptions(options);
- > }
- > });
- >
- > var circle = new Circle({ origin: Point(1, 4) });
- >
- > circle.options
- > // => { radius: 1, origin: Point(1,4) }
-
- Accessors:
- There are builtin methods to automatically write options accessors. All those
- methods can take either an array of option names nor option names as arguments.
- Notice that those methods won't override an accessor method if already present.
-
- * <optionsGetter> creates getters
- * <optionsSetter> creates setters
- * <optionsAccessor> creates both getters and setters
-
- Common usage is to invoke them on a class to create accessors for all instances
- of this class.
- Invoking those methods on a class has the same effect as invoking them on the class prototype.
- See <classMethod> for more details.
-
- Example:
- > // Creates getter and setter for the "radius" options of circles
- > Circle.optionsAccessor('radius');
- >
- > circle.setRadius(4);
- > // 4
- >
- > circle.getRadius();
- > // => 4 (circle.options.radius)
-
- Inheritance support:
- Subclasses can refine default *options* values, after a first instance call on setOptions,
- *options* attribute will hold all default options values coming from the inheritance hierarchy.
-*/
-
-(function() {
- UI.Options = {
- methodsAdded: function(klass) {
- klass.classMethod($w(' setOptions allOptions optionsGetter optionsSetter optionsAccessor '));
- },
-
- // Group: Methods
-
- /*
- Method: setOptions
- Extends object's *options* property with the given object
- */
- setOptions: function(options) {
- if (!this.hasOwnProperty('options'))
- this.options = this.allOptions();
-
- this.options = Object.extend(this.options, options || {});
- },
-
- /*
- Method: allOptions
- Computes the complete default options hash made by reverse extending all superclasses
- default options.
-
- > Widget.prototype.allOptions();
- */
- allOptions: function() {
- var superclass = this.constructor.superclass, ancestor = superclass && superclass.prototype;
- return (ancestor && ancestor.allOptions) ?
- Object.extend(ancestor.allOptions(), this.options) :
- Object.clone(this.options);
- },
-
- /*
- Method: optionsGetter
- Creates default getters for option names given as arguments.
- With no argument, creates getters for all option names.
- */
- optionsGetter: function() {
- addOptionsAccessors(this, arguments, false);
- },
-
- /*
- Method: optionsSetter
- Creates default setters for option names given as arguments.
- With no argument, creates setters for all option names.
- */
- optionsSetter: function() {
- addOptionsAccessors(this, arguments, true);
- },
-
- /*
- Method: optionsAccessor
- Creates default getters/setters for option names given as arguments.
- With no argument, creates accessors for all option names.
- */
- optionsAccessor: function() {
- this.optionsGetter.apply(this, arguments);
- this.optionsSetter.apply(this, arguments);
- }
- };
-
- // Internal
- function addOptionsAccessors(receiver, names, areSetters) {
- names = $A(names).flatten();
-
- if (names.empty())
- names = Object.keys(receiver.allOptions());
-
- names.each(function(name) {
- var accessorName = (areSetters ? 'set' : 'get') + name.camelcase();
-
- receiver[accessorName] = receiver[accessorName] || (areSetters ?
- // Setter
- function(value) { return this.options[name] = value } :
- // Getter
- function() { return this.options[name] });
- });
- }
-})();
-/*
- Class: UI.Carousel
-
- Main class to handle a carousel of elements in a page. A carousel :
- * could be vertical or horizontal
- * works with liquid layout
- * is designed by CSS
-
- Assumptions:
- * Elements should be from the same size
-
- Example:
- > ...
- > <div id="horizontal_carousel">
- > <div class="previous_button"></div>
- > <div class="container">
- > <ul>
- > <li> What ever you like</li>
- > </ul>
- > </div>
- > <div class="next_button"></div>
- > </div>
- > <script>
- > new UI.Carousel("horizontal_carousel");
- > </script>
- > ...
-*/
-UI.Carousel = Class.create(UI.Options, {
- // Group: Options
- options: {
- // Property: direction
- // Can be horizontal or vertical, horizontal by default
- direction : "horizontal",
-
- // Property: previousButton
- // Selector of previous button inside carousel element, ".previous_button" by default,
- // set it to false to ignore previous button
- previousButton : ".previous_button",
-
- // Property: nextButton
- // Selector of next button inside carousel element, ".next_button" by default,
- // set it to false to ignore next button
- nextButton : ".next_button",
-
- // Property: container
- // Selector of carousel container inside carousel element, ".container" by default,
- container : ".container",
-
- // Property: scrollInc
- // Define the maximum number of elements that gonna scroll each time, auto by default
- scrollInc : "auto",
-
- // Property: disabledButtonSuffix
- // Define the suffix classanme used when a button get disabled, to '_disabled' by default
- // Previous button classname will be previous_button_disabled
- disabledButtonSuffix : '_disabled',
-
- // Property: overButtonSuffix
- // Define the suffix classanme used when a button has a rollover status, '_over' by default
- // Previous button classname will be previous_button_over
- overButtonSuffix : '_over'
- },
-
- /*
- Group: Attributes
-
- Property: element
- DOM element containing the carousel
-
- Property: id
- DOM id of the carousel's element
-
- Property: container
- DOM element containing the carousel's elements
-
- Property: elements
- Array containing the carousel's elements as DOM elements
-
- Property: previousButton
- DOM id of the previous button
-
- Property: nextButton
- DOM id of the next button
-
- Property: posAttribute
- Define if the positions are from left or top
-
- Property: dimAttribute
- Define if the dimensions are horizontal or vertical
-
- Property: elementSize
- Size of each element, it's an integer
-
- Property: nbVisible
- Number of visible elements, it's a float
-
- Property: animating
- Define whether the carousel is in animation or not
- */
-
- /*
- Group: Events
- List of events fired by a carousel
-
- Notice: Carousel custom events are automatically namespaced in "carousel:" (see Prototype custom events).
-
- Examples:
- This example will observe all carousels
- > document.observe('carousel:scroll:ended', function(event) {
- > alert("Carousel with id " + event.memo.carousel.id + " has just been scrolled");
- > });
-
- This example will observe only this carousel
- > new UI.Carousel('horizontal_carousel').observe('scroll:ended', function(event) {
- > alert("Carousel with id " + event.memo.carousel.id + " has just been scrolled");
- > });
-
- Property: previousButton:enabled
- Fired when the previous button has just been enabled
-
- Property: previousButton:disabled
- Fired when the previous button has just been disabled
-
- Property: nextButton:enabled
- Fired when the next button has just been enabled
-
- Property: nextButton:disabled
- Fired when the next button has just been disabled
-
- Property: scroll:started
- Fired when a scroll has just started
-
- Property: scroll:ended
- Fired when a scroll has been done,
- memo.shift = number of elements scrolled, it's a float
-
- Property: sizeUpdated
- Fired when the carousel size has just been updated.
- Tips: memo.carousel.currentSize() = the new carousel size
- */
-
- // Group: Constructor
-
- /*
- Method: initialize
- Constructor function, should not be called directly
-
- Parameters:
- element - DOM element
- options - (Hash) list of optional parameters
-
- Returns:
- this
- */
- initialize: function(element, options) {
- this.setOptions(options);
- this.element = $(element);
- this.id = this.element.id;
- this.container = this.element.down(this.options.container).firstDescendant();
- this.elements = this.container.childElements();
- this.previousButton = this.options.previousButton == false ? null : this.element.down(this.options.previousButton);
- this.nextButton = this.options.nextButton == false ? null : this.element.down(this.options.nextButton);
-
- this.posAttribute = (this.options.direction == "horizontal" ? "left" : "top");
- this.dimAttribute = (this.options.direction == "horizontal" ? "width" : "height");
-
- this.elementSize = this.computeElementSize();
- this.nbVisible = this.currentSize() / this.elementSize;
-
- var scrollInc = this.options.scrollInc;
- if (scrollInc == "auto")
- scrollInc = Math.floor(this.nbVisible);
- [ this.previousButton, this.nextButton ].each(function(button) {
- if (!button) return;
- var className = (button == this.nextButton ? "next_button" : "previous_button") + this.options.overButtonSuffix;
- button.clickHandler = this.scroll.bind(this, (button == this.nextButton ? -1 : 1) * scrollInc * this.elementSize);
- button.observe("click", button.clickHandler)
- .observe("mouseover", function() {button.addClassName(className)}.bind(this))
- .observe("mouseout", function() {button.removeClassName(className)}.bind(this));
- }, this);
- this.updateButtons();
- },
-
- // Group: Destructor
-
- /*
- Method: destroy
- Cleans up DOM and memory
- */
- destroy: function($super) {
- [ this.previousButton, this.nextButton ].each(function(button) {
- if (!button) return;
- button.stopObserving("click", button.clickHandler);
- }, this);
- this.element.remove();
- this.fire('destroyed');
- },
-
- // Group: Event handling
-
- /*
- Method: fire
- Fires a carousel custom event automatically namespaced in "carousel:" (see Prototype custom events).
- The memo object contains a "carousel" property referring to the carousel.
-
- Example:
- > document.observe('carousel:scroll:ended', function(event) {
- > alert("Carousel with id " + event.memo.carousel.id + " has just been scrolled");
- > });
-
- Parameters:
- eventName - an event name
- memo - a memo object
-
- Returns:
- fired event
- */
- fire: function(eventName, memo) {
- memo = memo || { };
- memo.carousel = this;
- return this.element.fire('carousel:' + eventName, memo);
- },
-
- /*
- Method: observe
- Observe a carousel event with a handler function automatically bound to the carousel
-
- Parameters:
- eventName - an event name
- handler - a handler function
-
- Returns:
- this
- */
- observe: function(eventName, handler) {
- this.element.observe('carousel:' + eventName, handler.bind(this));
- return this;
- },
-
- /*
- Method: stopObserving
- Unregisters a carousel event, it must take the same parameters as this.observe (see Prototype stopObserving).
-
- Parameters:
- eventName - an event name
- handler - a handler function
-
- Returns:
- this
- */
- stopObserving: function(eventName, handler) {
- this.element.stopObserving('carousel:' + eventName, handler);
- return this;
- },
-
- // Group: Actions
-
- /*
- Method: checkScroll
- Check scroll position to avoid unused space at right or bottom
-
- Parameters:
- position - position to check
- updatePosition - should the container position be updated ? true/false
-
- Returns:
- position
- */
- checkScroll: function(position, updatePosition) {
- if (position > 0)
- position = 0;
- else {
- var limit = this.elements.last().positionedOffset()[this.posAttribute] + this.elementSize;
- var carouselSize = this.currentSize();
-
- if (position + limit < carouselSize)
- position += carouselSize - (position + limit);
- position = Math.min(position, 0);
- }
- if (updatePosition)
- this.container.style[this.posAttribute] = position + "px";
-
- return position;
- },
-
- /*
- Method: scroll
- Scrolls carousel from maximum deltaPixel
-
- Parameters:
- deltaPixel - a float
-
- Returns:
- this
- */
- scroll: function(deltaPixel) {
- if (this.animating)
- return this;
-
- // Compute new position
- var position = this.currentPosition() + deltaPixel;
-
- // Check bounds
- position = this.checkScroll(position, false);
-
- // Compute shift to apply
- deltaPixel = position - this.currentPosition();
- if (deltaPixel != 0) {
- this.animating = true;
- this.fire("scroll:started");
-
- var that = this;
- // Move effects
- this.container.morph("opacity:0.5", {duration: 0.2, afterFinish: function() {
- that.container.morph(that.posAttribute + ": " + position + "px", {
- duration: 0.4,
- delay: 0.2,
- afterFinish: function() {
- that.container.morph("opacity:1", {
- duration: 0.2,
- afterFinish: function() {
- that.animating = false;
- that.updateButtons()
- .fire("scroll:ended", { shift: deltaPixel / that.currentSize() });
- }
- });
- }
- });
- }});
- }
- return this;
- },
-
- /*
- Method: scrollTo
- Scrolls carousel, so that element with specified index is the left-most.
- This method is convenient when using carousel in a tabbed navigation.
- Clicking on first tab should scroll first container into view, clicking on a fifth - fifth one, etc.
- Indexing starts with 0.
-
- Parameters:
- Index of an element which will be a left-most visible in the carousel
-
- Returns:
- this
- */
- scrollTo: function(index) {
- if (this.animating || index < 0 || index > this.elements.length || index == this.currentIndex() || isNaN(parseInt(index)))
- return this;
- return this.scroll((this.currentIndex() - index) * this.elementSize);
- },
-
- /*
- Method: updateButtons
- Update buttons status to enabled or disabled
- Them status is defined by classNames and fired as carousel's custom events
-
- Returns:
- this
- */
- updateButtons: function() {
- this.updatePreviousButton();
- this.updateNextButton();
- return this;
- },
-
- updatePreviousButton: function() {
- var position = this.currentPosition();
- var previousClassName = "previous_button" + this.options.disabledButtonSuffix;
-
- if (this.previousButton.hasClassName(previousClassName) && position != 0) {
- this.previousButton.removeClassName(previousClassName);
- this.fire('previousButton:enabled');
- }
- if (!this.previousButton.hasClassName(previousClassName) && position == 0) {
- this.previousButton.addClassName(previousClassName);
- this.fire('previousButton:disabled');
- }
- },
-
- updateNextButton: function() {
- var lastPosition = this.currentLastPosition();
- var size = this.currentSize();
- var nextClassName = "next_button" + this.options.disabledButtonSuffix;
-
- if (this.nextButton.hasClassName(nextClassName) && lastPosition != size) {
- this.nextButton.removeClassName(nextClassName);
- this.fire('nextButton:enabled');
- }
- if (!this.nextButton.hasClassName(nextClassName) && lastPosition == size) {
- this.nextButton.addClassName(nextClassName);
- this.fire('nextButton:disabled');
- }
- },
-
- // Group: Size and Position
-
- /*
- Method: computeElementSize
- Return elements size in pixel, height or width depends on carousel orientation.
-
- Returns:
- an integer value
- */
- computeElementSize: function() {
- return this.elements.first().getDimensions()[this.dimAttribute];
- },
-
- /*
- Method: currentIndex
- Returns current visible index of a carousel.
- For example, a horizontal carousel with image #3 on left will return 3 and with half of image #3 will return 3.5
- Don't forget that the first image have an index 0
-
- Returns:
- a float value
- */
- currentIndex: function() {
- return - this.currentPosition() / this.elementSize;
- },
-
- /*
- Method: currentLastPosition
- Returns the current position from the end of the last element. This value is in pixel.
-
- Returns:
- an integer value, if no images a present it will return 0
- */
- currentLastPosition: function() {
- if (this.container.childElements().empty())
- return 0;
- return this.currentPosition() +
- this.elements.last().positionedOffset()[this.posAttribute] +
- this.elementSize;
- },
-
- /*
- Method: currentPosition
- Returns the current position in pixel.
- Tips: To get the position in elements use currentIndex()
-
- Returns:
- an integer value
- */
- currentPosition: function() {
- return this.container.getNumStyle(this.posAttribute);
- },
-
- /*
- Method: currentSize
- Returns the current size of the carousel in pixel
-
- Returns:
- Carousel's size in pixel
- */
- currentSize: function() {
- return this.container.parentNode.getDimensions()[this.dimAttribute];
- },
-
- /*
- Method: updateSize
- Should be called if carousel size has been changed (usually called with a liquid layout)
-
- Returns:
- this
- */
- updateSize: function() {
- this.nbVisible = this.currentSize() / this.elementSize;
- var scrollInc = this.options.scrollInc;
- if (scrollInc == "auto")
- scrollInc = Math.floor(this.nbVisible);
-
- [ this.previousButton, this.nextButton ].each(function(button) {
- if (!button) return;
- button.stopObserving("click", button.clickHandler);
- button.clickHandler = this.scroll.bind(this, (button == this.nextButton ? -1 : 1) * scrollInc * this.elementSize);
- button.observe("click", button.clickHandler);
- }, this);
-
- this.checkScroll(this.currentPosition(), true);
- this.updateButtons().fire('sizeUpdated');
- return this;
- }
-});
-/*
- Class: UI.Ajax.Carousel
-
- Gives the AJAX power to carousels. An AJAX carousel :
- * Use AJAX to add new elements on the fly
-
- Example:
- > new UI.Ajax.Carousel("horizontal_carousel",
- > {url: "get-more-elements", elementSize: 250});
-*/
-UI.Ajax.Carousel = Class.create(UI.Carousel, {
- // Group: Options
- //
- // Notice:
- // It also include of all carousel's options
- options: {
- // Property: elementSize
- // Required, it define the size of all elements
- elementSize : -1,
-
- // Property: url
- // Required, it define the URL used by AJAX carousel to request new elements details
- url : null
- },
-
- /*
- Group: Attributes
-
- Notice:
- It also include of all carousel's attributes
-
- Property: elementSize
- Size of each elements, it's an integer
-
- Property: endIndex
- Index of the last loaded element
-
- Property: hasMore
- Flag to define if there's still more elements to load
-
- Property: requestRunning
- Define whether a request is processing or not
-
- Property: updateHandler
- Callback to update carousel, usually used after request success
-
- Property: url
- URL used to request additional elements
- */
-
- /*
- Group: Events
- List of events fired by an AJAX carousel, it also include of all carousel's custom events
-
- Property: request:started
- Fired when the request has just started
-
- Property: request:ended
- Fired when the request has succeed
- */
-
- // Group: Constructor
-
- /*
- Method: initialize
- Constructor function, should not be called directly
-
- Parameters:
- element - DOM element
- options - (Hash) list of optional parameters
-
- Returns:
- this
- */
- initialize: function($super, element, options) {
- if (!options.url)
- throw("url option is required for UI.Ajax.Carousel");
- if (!options.elementSize)
- throw("elementSize option is required for UI.Ajax.Carousel");
-
- $super(element, options);
-
- this.endIndex = 0;
- this.hasMore = true;
-
- // Cache handlers
- this.updateHandler = this.update.bind(this);
- this.updateAndScrollHandler = function(nbElements, transport, json) {
- this.update(transport, json);
- this.scroll(nbElements);
- }.bind(this);
-
- // Run first ajax request to fill the carousel
- this.runRequest.bind(this).defer({parameters: {from: 0, to: Math.floor(this.nbVisible)}, onSuccess: this.updateHandler});
- },
-
- // Group: Actions
-
- /*
- Method: runRequest
- Request the new elements details
-
- Parameters:
- options - (Hash) list of optional parameters
-
- Returns:
- this
- */
- runRequest: function(options) {
- this.requestRunning = true;
- //alert("Asking for: " + options.parameters.from + " - " + options.parameters.to);
- new Ajax.Request(this.options.url, Object.extend({method: "GET"}, options));
- this.fire("request:started");
- return this;
- },
-
- /*
- Method: scroll
- Scrolls carousel from maximum deltaPixel
-
- Parameters:
- deltaPixel - a float
-
- Returns:
- this
- */
- scroll: function($super, deltaPixel) {
- if (this.animating || this.requestRunning)
- return this;
-
- var nbElements = (-deltaPixel) / this.elementSize;
- // Check if there is not enough
- if (this.hasMore && nbElements > 0 && this.currentIndex() + this.nbVisible + nbElements - 1 > this.endIndex) {
- var from = this.endIndex + 1;
- var to = Math.floor(from + this.nbVisible - 1);
- this.runRequest({parameters: {from: from, to: to}, onSuccess: this.updateAndScrollHandler.curry(deltaPixel).bind(this)});
- return this;
- }
- else
- $super(deltaPixel);
- },
-
- /*
- Method: update
- Update the carousel
-
- Parameters:
- transport - XMLHttpRequest object
- json - JSON object
-
- Returns:
- this
- */
- update: function(transport, json) {
- this.requestRunning = false;
- this.fire("request:ended");
- if (!json)
- json = transport.responseJSON;
- this.hasMore = json.more;
-
- this.endIndex = Math.max(this.endIndex, json.to);
- this.elements = this.container.insert({bottom: json.html}).childElements();
- return this.updateButtons();
- },
-
- // Group: Size and Position
-
- /*
- Method: computeElementSize
- Return elements size in pixel
-
- Returns:
- an integer value
- */
- computeElementSize: function() {
- return this.options.elementSize;
- },
-
- /*
- Method: updateSize
- Should be called if carousel size has been changed (usually called with a liquid layout)
-
- Returns:
- this
- */
- updateSize: function($super) {
- var nbVisible = this.nbVisible;
- $super();
- // If we have enough space for at least a new element
- if (Math.floor(this.nbVisible) - Math.floor(nbVisible) >= 1 && this.hasMore) {
- if (this.currentIndex() + Math.floor(this.nbVisible) >= this.endIndex) {
- var nbNew = Math.floor(this.currentIndex() + Math.floor(this.nbVisible) - this.endIndex);
- this.runRequest({parameters: {from: this.endIndex + 1, to: this.endIndex + nbNew}, onSuccess: this.updateHandler});
- }
- }
- return this;
- },
-
- updateNextButton: function($super) {
- var lastPosition = this.currentLastPosition();
- var size = this.currentSize();
- var nextClassName = "next_button" + this.options.disabledButtonSuffix;
-
- if (this.nextButton.hasClassName(nextClassName) && lastPosition != size) {
- this.nextButton.removeClassName(nextClassName);
- this.fire('nextButton:enabled');
- }
- if (!this.nextButton.hasClassName(nextClassName) && lastPosition == size && !this.hasMore) {
- this.nextButton.addClassName(nextClassName);
- this.fire('nextButton:disabled');
- }
- }
-});
+++ /dev/null
-/**
- * Copyright 2006, David Spurr (http://www.defusion.org.uk/)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- * * Neither the name of the David Spurr nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * http://www.opensource.org/licenses/bsd-license.php
- *
- * See scriptaculous.js for full scriptaculous licence
- */
-
-var CropDraggable=Class.create();
-Object.extend(Object.extend(CropDraggable.prototype,Draggable.prototype),{initialize:function(_1){
-this.options=Object.extend({drawMethod:function(){
-}},arguments[1]||{});
-this.element=$(_1);
-this.handle=this.element;
-this.delta=this.currentDelta();
-this.dragging=false;
-this.eventMouseDown=this.initDrag.bindAsEventListener(this);
-Event.observe(this.handle,"mousedown",this.eventMouseDown);
-Draggables.register(this);
-},draw:function(_2){
-var _3=Position.cumulativeOffset(this.element);
-var d=this.currentDelta();
-_3[0]-=d[0];
-_3[1]-=d[1];
-var p=[0,1].map(function(i){
-return (_2[i]-_3[i]-this.offset[i]);
-}.bind(this));
-this.options.drawMethod(p);
-}});
-var Cropper={};
-Cropper.Img=Class.create();
-Cropper.Img.prototype={initialize:function(_7,_8){
-this.options=Object.extend({ratioDim:{x:0,y:0},minWidth:0,minHeight:0,displayOnInit:false,onEndCrop:Prototype.emptyFunction,captureKeys:true,onloadCoords:null,maxWidth:0,maxHeight:0},_8||{});
-this.img=$(_7);
-this.clickCoords={x:0,y:0};
-this.dragging=false;
-this.resizing=false;
-this.isWebKit=/Konqueror|Safari|KHTML/.test(navigator.userAgent);
-this.isIE=/MSIE/.test(navigator.userAgent);
-this.isOpera8=/Opera\s[1-8]/.test(navigator.userAgent);
-this.ratioX=0;
-this.ratioY=0;
-this.attached=false;
-this.fixedWidth=(this.options.maxWidth>0&&(this.options.minWidth>=this.options.maxWidth));
-this.fixedHeight=(this.options.maxHeight>0&&(this.options.minHeight>=this.options.maxHeight));
-if(typeof this.img=="undefined"){
-return;
-}
-if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0){
-var _c=this.getGCD(this.options.ratioDim.x,this.options.ratioDim.y);
-this.ratioX=this.options.ratioDim.x/_c;
-this.ratioY=this.options.ratioDim.y/_c;
-}
-this.subInitialize();
-if(this.img.complete||this.isWebKit){
-this.onLoad();
-}else{
-Event.observe(this.img,"load",this.onLoad.bindAsEventListener(this));
-}
-},getGCD:function(a,b){
-if(b==0){
-return a;
-}
-return this.getGCD(b,a%b);
-},onLoad:function(){
-var _f="imgCrop_";
-var _10=this.img.parentNode;
-var _11="";
-if(this.isOpera8){
-_11=" opera8";
-}
-this.imgWrap=Builder.node("div",{"class":_f+"wrap"+_11});
-this.north=Builder.node("div",{"class":_f+"overlay "+_f+"north"},[Builder.node("span")]);
-this.east=Builder.node("div",{"class":_f+"overlay "+_f+"east"},[Builder.node("span")]);
-this.south=Builder.node("div",{"class":_f+"overlay "+_f+"south"},[Builder.node("span")]);
-this.west=Builder.node("div",{"class":_f+"overlay "+_f+"west"},[Builder.node("span")]);
-var _12=[this.north,this.east,this.south,this.west];
-this.dragArea=Builder.node("div",{"class":_f+"dragArea"},_12);
-this.handleN=Builder.node("div",{"class":_f+"handle "+_f+"handleN"});
-this.handleNE=Builder.node("div",{"class":_f+"handle "+_f+"handleNE"});
-this.handleE=Builder.node("div",{"class":_f+"handle "+_f+"handleE"});
-this.handleSE=Builder.node("div",{"class":_f+"handle "+_f+"handleSE"});
-this.handleS=Builder.node("div",{"class":_f+"handle "+_f+"handleS"});
-this.handleSW=Builder.node("div",{"class":_f+"handle "+_f+"handleSW"});
-this.handleW=Builder.node("div",{"class":_f+"handle "+_f+"handleW"});
-this.handleNW=Builder.node("div",{"class":_f+"handle "+_f+"handleNW"});
-this.selArea=Builder.node("div",{"class":_f+"selArea"},[Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeNorth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeEast"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeSouth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeWest"},[Builder.node("span")]),this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW,Builder.node("div",{"class":_f+"clickArea"})]);
-this.imgWrap.appendChild(this.img);
-this.imgWrap.appendChild(this.dragArea);
-this.dragArea.appendChild(this.selArea);
-this.dragArea.appendChild(Builder.node("div",{"class":_f+"clickArea"}));
-_10.appendChild(this.imgWrap);
-this.startDragBind=this.startDrag.bindAsEventListener(this);
-Event.observe(this.dragArea,"mousedown",this.startDragBind);
-this.onDragBind=this.onDrag.bindAsEventListener(this);
-Event.observe(document,"mousemove",this.onDragBind);
-this.endCropBind=this.endCrop.bindAsEventListener(this);
-Event.observe(document,"mouseup",this.endCropBind);
-this.resizeBind=this.startResize.bindAsEventListener(this);
-this.handles=[this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW];
-this.registerHandles(true);
-if(this.options.captureKeys){
-this.keysBind=this.handleKeys.bindAsEventListener(this);
-Event.observe(document,"keypress",this.keysBind);
-}
-new CropDraggable(this.selArea,{drawMethod:this.moveArea.bindAsEventListener(this)});
-this.setParams();
-},registerHandles:function(_13){
-for(var i=0;i<this.handles.length;i++){
-var _15=$(this.handles[i]);
-if(_13){
-var _16=false;
-if(this.fixedWidth&&this.fixedHeight){
-_16=true;
-}else{
-if(this.fixedWidth||this.fixedHeight){
-var _17=_15.className.match(/([S|N][E|W])$/);
-var _18=_15.className.match(/(E|W)$/);
-var _19=_15.className.match(/(N|S)$/);
-if(_17){
-_16=true;
-}else{
-if(this.fixedWidth&&_18){
-_16=true;
-}else{
-if(this.fixedHeight&&_19){
-_16=true;
-}
-}
-}
-}
-}
-if(_16){
-_15.hide();
-}else{
-Event.observe(_15,"mousedown",this.resizeBind);
-}
-}else{
-_15.show();
-Event.stopObserving(_15,"mousedown",this.resizeBind);
-}
-}
-},setParams:function(){
-this.imgW=this.img.width;
-this.imgH=this.img.height;
-$(this.north).setStyle({height:0});
-$(this.east).setStyle({width:0,height:0});
-$(this.south).setStyle({height:0});
-$(this.west).setStyle({width:0,height:0});
-$(this.imgWrap).setStyle({"width":this.imgW+"px","height":this.imgH+"px"});
-$(this.selArea).hide();
-var _1a={x1:0,y1:0,x2:0,y2:0};
-var _1b=false;
-if(this.options.onloadCoords!=null){
-_1a=this.cloneCoords(this.options.onloadCoords);
-_1b=true;
-}else{
-if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0){
-_1a.x1=Math.ceil((this.imgW-this.options.ratioDim.x)/2);
-_1a.y1=Math.ceil((this.imgH-this.options.ratioDim.y)/2);
-_1a.x2=_1a.x1+this.options.ratioDim.x;
-_1a.y2=_1a.y1+this.options.ratioDim.y;
-_1b=true;
-}
-}
-this.setAreaCoords(_1a,false,false,1);
-if(this.options.displayOnInit&&_1b){
-this.selArea.show();
-this.drawArea();
-this.endCrop();
-}
-this.attached=true;
-},remove:function(){
-if(this.attached){
-this.attached=false;
-this.imgWrap.parentNode.insertBefore(this.img,this.imgWrap);
-this.imgWrap.parentNode.removeChild(this.imgWrap);
-Event.stopObserving(this.dragArea,"mousedown",this.startDragBind);
-Event.stopObserving(document,"mousemove",this.onDragBind);
-Event.stopObserving(document,"mouseup",this.endCropBind);
-this.registerHandles(false);
-if(this.options.captureKeys){
-Event.stopObserving(document,"keypress",this.keysBind);
-}
-}
-},reset:function(){
-if(!this.attached){
-this.onLoad();
-}else{
-this.setParams();
-}
-this.endCrop();
-},handleKeys:function(e){
-var dir={x:0,y:0};
-if(!this.dragging){
-switch(e.keyCode){
-case (37):
-dir.x=-1;
-break;
-case (38):
-dir.y=-1;
-break;
-case (39):
-dir.x=1;
-break;
-case (40):
-dir.y=1;
-break;
-}
-if(dir.x!=0||dir.y!=0){
-if(e.shiftKey){
-dir.x*=10;
-dir.y*=10;
-}
-this.moveArea([this.areaCoords.x1+dir.x,this.areaCoords.y1+dir.y]);
-Event.stop(e);
-}
-}
-},calcW:function(){
-return (this.areaCoords.x2-this.areaCoords.x1);
-},calcH:function(){
-return (this.areaCoords.y2-this.areaCoords.y1);
-},moveArea:function(_1e){
-this.setAreaCoords({x1:_1e[0],y1:_1e[1],x2:_1e[0]+this.calcW(),y2:_1e[1]+this.calcH()},true,false);
-this.drawArea();
-},cloneCoords:function(_1f){
-return {x1:_1f.x1,y1:_1f.y1,x2:_1f.x2,y2:_1f.y2};
-},setAreaCoords:function(_20,_21,_22,_23,_24){
-if(_21){
-var _25=_20.x2-_20.x1;
-var _26=_20.y2-_20.y1;
-if(_20.x1<0){
-_20.x1=0;
-_20.x2=_25;
-}
-if(_20.y1<0){
-_20.y1=0;
-_20.y2=_26;
-}
-if(_20.x2>this.imgW){
-_20.x2=this.imgW;
-_20.x1=this.imgW-_25;
-}
-if(_20.y2>this.imgH){
-_20.y2=this.imgH;
-_20.y1=this.imgH-_26;
-}
-}else{
-if(_20.x1<0){
-_20.x1=0;
-}
-if(_20.y1<0){
-_20.y1=0;
-}
-if(_20.x2>this.imgW){
-_20.x2=this.imgW;
-}
-if(_20.y2>this.imgH){
-_20.y2=this.imgH;
-}
-if(_23!=null){
-if(this.ratioX>0){
-this.applyRatio(_20,{x:this.ratioX,y:this.ratioY},_23,_24);
-}else{
-if(_22){
-this.applyRatio(_20,{x:1,y:1},_23,_24);
-}
-}
-var _27=[this.options.minWidth,this.options.minHeight];
-var _28=[this.options.maxWidth,this.options.maxHeight];
-if(_27[0]>0||_27[1]>0||_28[0]>0||_28[1]>0){
-var _29={a1:_20.x1,a2:_20.x2};
-var _2a={a1:_20.y1,a2:_20.y2};
-var _2b={min:0,max:this.imgW};
-var _2c={min:0,max:this.imgH};
-if((_27[0]!=0||_27[1]!=0)&&_22){
-if(_27[0]>0){
-_27[1]=_27[0];
-}else{
-if(_27[1]>0){
-_27[0]=_27[1];
-}
-}
-}
-if((_28[0]!=0||_28[0]!=0)&&_22){
-if(_28[0]>0&&_28[0]<=_28[1]){
-_28[1]=_28[0];
-}else{
-if(_28[1]>0&&_28[1]<=_28[0]){
-_28[0]=_28[1];
-}
-}
-}
-if(_27[0]>0){
-this.applyDimRestriction(_29,_27[0],_23.x,_2b,"min");
-}
-if(_27[1]>1){
-this.applyDimRestriction(_2a,_27[1],_23.y,_2c,"min");
-}
-if(_28[0]>0){
-this.applyDimRestriction(_29,_28[0],_23.x,_2b,"max");
-}
-if(_28[1]>1){
-this.applyDimRestriction(_2a,_28[1],_23.y,_2c,"max");
-}
-_20={x1:_29.a1,y1:_2a.a1,x2:_29.a2,y2:_2a.a2};
-}
-}
-}
-this.areaCoords=_20;
-},applyDimRestriction:function(_2d,val,_2f,_30,_31){
-var _32;
-if(_31=="min"){
-_32=((_2d.a2-_2d.a1)<val);
-}else{
-_32=((_2d.a2-_2d.a1)>val);
-}
-if(_32){
-if(_2f==1){
-_2d.a2=_2d.a1+val;
-}else{
-_2d.a1=_2d.a2-val;
-}
-if(_2d.a1<_30.min){
-_2d.a1=_30.min;
-_2d.a2=val;
-}else{
-if(_2d.a2>_30.max){
-_2d.a1=_30.max-val;
-_2d.a2=_30.max;
-}
-}
-}
-},applyRatio:function(_33,_34,_35,_36){
-var _37;
-if(_36=="N"||_36=="S"){
-_37=this.applyRatioToAxis({a1:_33.y1,b1:_33.x1,a2:_33.y2,b2:_33.x2},{a:_34.y,b:_34.x},{a:_35.y,b:_35.x},{min:0,max:this.imgW});
-_33.x1=_37.b1;
-_33.y1=_37.a1;
-_33.x2=_37.b2;
-_33.y2=_37.a2;
-}else{
-_37=this.applyRatioToAxis({a1:_33.x1,b1:_33.y1,a2:_33.x2,b2:_33.y2},{a:_34.x,b:_34.y},{a:_35.x,b:_35.y},{min:0,max:this.imgH});
-_33.x1=_37.a1;
-_33.y1=_37.b1;
-_33.x2=_37.a2;
-_33.y2=_37.b2;
-}
-},applyRatioToAxis:function(_38,_39,_3a,_3b){
-var _3c=Object.extend(_38,{});
-var _3d=_3c.a2-_3c.a1;
-var _3e=Math.floor(_3d*_39.b/_39.a);
-var _3f;
-var _40;
-var _41=null;
-if(_3a.b==1){
-_3f=_3c.b1+_3e;
-if(_3f>_3b.max){
-_3f=_3b.max;
-_41=_3f-_3c.b1;
-}
-_3c.b2=_3f;
-}else{
-_3f=_3c.b2-_3e;
-if(_3f<_3b.min){
-_3f=_3b.min;
-_41=_3f+_3c.b2;
-}
-_3c.b1=_3f;
-}
-if(_41!=null){
-_40=Math.floor(_41*_39.a/_39.b);
-if(_3a.a==1){
-_3c.a2=_3c.a1+_40;
-}else{
-_3c.a1=_3c.a1=_3c.a2-_40;
-}
-}
-return _3c;
-},drawArea:function(){
-var _42=this.calcW();
-var _43=this.calcH();
-var px="px";
-var _45=[this.areaCoords.x1+px,this.areaCoords.y1+px,_42+px,_43+px,this.areaCoords.x2+px,this.areaCoords.y2+px,(this.img.width-this.areaCoords.x2)+px,(this.img.height-this.areaCoords.y2)+px];
-var _46=this.selArea.style;
-_46.left=_45[0];
-_46.top=_45[1];
-_46.width=_45[2];
-_46.height=_45[3];
-var _47=Math.ceil((_42-6)/2)+px;
-var _48=Math.ceil((_43-6)/2)+px;
-this.handleN.style.left=_47;
-this.handleE.style.top=_48;
-this.handleS.style.left=_47;
-this.handleW.style.top=_48;
-this.north.style.height=_45[1];
-var _49=this.east.style;
-_49.top=_45[1];
-_49.height=_45[3];
-_49.left=_45[4];
-_49.width=_45[6];
-var _4a=this.south.style;
-_4a.top=_45[5];
-_4a.height=_45[7];
-var _4b=this.west.style;
-_4b.top=_45[1];
-_4b.height=_45[3];
-_4b.width=_45[0];
-this.subDrawArea();
-this.forceReRender();
-},forceReRender:function(){
-if(this.isIE||this.isWebKit){
-var n=document.createTextNode(" ");
-var d,el,fixEL,i;
-if(this.isIE){
-fixEl=this.selArea;
-}else{
-if(this.isWebKit){
-fixEl=document.getElementsByClassName("imgCrop_marqueeSouth",this.imgWrap)[0];
-d=Builder.node("div","");
-d.style.visibility="hidden";
-var _4e=["SE","S","SW"];
-for(i=0;i<_4e.length;i++){
-el=document.getElementsByClassName("imgCrop_handle"+_4e[i],this.selArea)[0];
-if(el.childNodes.length){
-el.removeChild(el.childNodes[0]);
-}
-el.appendChild(d);
-}
-}
-}
-fixEl.appendChild(n);
-fixEl.removeChild(n);
-}
-},startResize:function(e){
-this.startCoords=this.cloneCoords(this.areaCoords);
-this.resizing=true;
-this.resizeHandle=Event.element(e).classNames().toString().replace(/([^N|NE|E|SE|S|SW|W|NW])+/,"");
-Event.stop(e);
-},startDrag:function(e){
-this.selArea.show();
-this.clickCoords=this.getCurPos(e);
-this.setAreaCoords({x1:this.clickCoords.x,y1:this.clickCoords.y,x2:this.clickCoords.x,y2:this.clickCoords.y},false,false,null);
-this.dragging=true;
-this.onDrag(e);
-Event.stop(e);
-},getCurPos:function(e){
-var el=this.imgWrap,wrapOffsets=Position.cumulativeOffset(el);
-while(el.nodeName!="BODY"){
-wrapOffsets[1]-=el.scrollTop||0;
-wrapOffsets[0]-=el.scrollLeft||0;
-el=el.parentNode;
-}
-return curPos={x:Event.pointerX(e)-wrapOffsets[0],y:Event.pointerY(e)-wrapOffsets[1]};
-},onDrag:function(e){
-if(this.dragging||this.resizing){
-var _54=null;
-var _55=this.getCurPos(e);
-var _56=this.cloneCoords(this.areaCoords);
-var _57={x:1,y:1};
-if(this.dragging){
-if(_55.x<this.clickCoords.x){
-_57.x=-1;
-}
-if(_55.y<this.clickCoords.y){
-_57.y=-1;
-}
-this.transformCoords(_55.x,this.clickCoords.x,_56,"x");
-this.transformCoords(_55.y,this.clickCoords.y,_56,"y");
-}else{
-if(this.resizing){
-_54=this.resizeHandle;
-if(_54.match(/E/)){
-this.transformCoords(_55.x,this.startCoords.x1,_56,"x");
-if(_55.x<this.startCoords.x1){
-_57.x=-1;
-}
-}else{
-if(_54.match(/W/)){
-this.transformCoords(_55.x,this.startCoords.x2,_56,"x");
-if(_55.x<this.startCoords.x2){
-_57.x=-1;
-}
-}
-}
-if(_54.match(/N/)){
-this.transformCoords(_55.y,this.startCoords.y2,_56,"y");
-if(_55.y<this.startCoords.y2){
-_57.y=-1;
-}
-}else{
-if(_54.match(/S/)){
-this.transformCoords(_55.y,this.startCoords.y1,_56,"y");
-if(_55.y<this.startCoords.y1){
-_57.y=-1;
-}
-}
-}
-}
-}
-this.setAreaCoords(_56,false,e.shiftKey,_57,_54);
-this.drawArea();
-Event.stop(e);
-}
-},transformCoords:function(_58,_59,_5a,_5b){
-var _5c=[_58,_59];
-if(_58>_59){
-_5c.reverse();
-}
-_5a[_5b+"1"]=_5c[0];
-_5a[_5b+"2"]=_5c[1];
-},endCrop:function(){
-this.dragging=false;
-this.resizing=false;
-this.options.onEndCrop(this.areaCoords,{width:this.calcW(),height:this.calcH()});
-},subInitialize:function(){
-},subDrawArea:function(){
-}};
-Cropper.ImgWithPreview=Class.create();
-Object.extend(Object.extend(Cropper.ImgWithPreview.prototype,Cropper.Img.prototype),{subInitialize:function(){
-this.hasPreviewImg=false;
-if(typeof (this.options.previewWrap)!="undefined"&&this.options.minWidth>0&&this.options.minHeight>0){
-this.previewWrap=$(this.options.previewWrap);
-this.previewImg=this.img.cloneNode(false);
-this.previewImg.id="imgCrop_"+this.previewImg.id;
-this.options.displayOnInit=true;
-this.hasPreviewImg=true;
-this.previewWrap.addClassName("imgCrop_previewWrap");
-this.previewWrap.setStyle({width:this.options.minWidth+"px",height:this.options.minHeight+"px"});
-this.previewWrap.appendChild(this.previewImg);
-}
-},subDrawArea:function(){
-if(this.hasPreviewImg){
-var _5d=this.calcW();
-var _5e=this.calcH();
-var _5f={x:this.imgW/_5d,y:this.imgH/_5e};
-var _60={x:_5d/this.options.minWidth,y:_5e/this.options.minHeight};
-var _61={w:Math.ceil(this.options.minWidth*_5f.x)+"px",h:Math.ceil(this.options.minHeight*_5f.y)+"px",x:"-"+Math.ceil(this.areaCoords.x1/_60.x)+"px",y:"-"+Math.ceil(this.areaCoords.y1/_60.y)+"px"};
-var _62=this.previewImg.style;
-_62.width=_61.w;
-_62.height=_61.h;
-_62.left=_61.x;
-_62.top=_61.y;
-}
-}});
-
+++ /dev/null
-// InPlaceEditor extension based somewhat on an example given in the
-// scriptaculous wiki
-Ajax.InPlaceEditor.prototype.__initialize = Ajax.InPlaceEditor.prototype.initialize;
-Ajax.InPlaceEditor.prototype.__getText = Ajax.InPlaceEditor.prototype.getText;
-Object.extend(Ajax.InPlaceEditor.prototype, {
- initialize: function(element, url, options) {
- this.__initialize(element, url, options);
- this.setOptions(options);
- // Remove this line to stop from auto-showing the
- // empty caption text on page load.
- this.checkEmpty();
- },
-
- setOptions: function(options) {
- this.options = Object.extend(Object.extend(this.options, {
- emptyClassName: 'inplaceeditor-empty'
- }),options||{});
- },
-
- checkEmpty: function() {
- if (this.element.innerHTML.length == 0) {
- emptyNode = new Element('span', {className: this.options.emptyClassName}).update(this.options.emptyText);
- this.element.appendChild(emptyNode);
- }
- },
-
- getText: function() {
- $(this.element).select('.' + this.options.emptyClassName).each(function(child) {
- this.element.removeChild(child);
- }.bind(this));
- return this.__getText();
- }
-});
-
-function tileExit(ipe, e)
-{
- ipe.checkEmpty();
-}
+++ /dev/null
-document.observe('dom:loaded', function() {
- Ansel.deleteFace = function(image_id, face_id)
- {
- new Ajax.Request(Ansel.ajax.editFaces.url,
- {
- method: 'post',
- parameters: {
- action: 'delete',
- image: image_id,
- face: face_id
- }
- });
- $('face' + face_id).remove();
- };
-
- Ansel.setFaceName = function(image_id, face_id)
- {
- new Ajax.Request(Ansel.ajax.editFaces.url,
- {
- method: 'post',
- parameters:
- {
- action: 'setname',
- face: face_id,
- image: image_id,
- facename: encodeURIComponent($F('facename' + face_id))
- },
- onComplete: function(r) {
- if (r.responseJSON.response == 1) {
- $('faces_widget_content').update(r.responseJSON.message);
- }
- }
- }
- );
- };
-
- Ansel.doFaceEdit = function(image_id)
- {
- $('faces_widget_content').update(Ansel.ajax.editFaces.text.loading);
- new Ajax.Request(Ansel.ajax.editFaces.url,
- {
- method: 'post',
- parameters:
- {
- action: 'process',
- image: image_id
- },
- onComplete: function(r) {
- if (r.responseJSON.response == 1) {
- $('faces_widget_content').update(r.responseJSON.message);
- }
- }
- }
- );
- };
-});
\ No newline at end of file
+++ /dev/null
-//<![CDATA[
-Event.observe(window, 'load', function() {
- // The number of unique, embedded instances
- var nodeCount = anselnodes.length;
-
- // Holds any lightbox json
- var lightboxData = new Array();
-
- // Iterate over each embedded instance and create the DOM elements.
- for (var n = 0; n < nodeCount; n++) {
-
- // j is the textual name of the container, used as a key
- var j = anselnodes[n];
-
- // Do we have any lightbox data?
- if (typeof anseljson[j]['lightbox'] != 'undefined') {
- lightboxData = lightboxData.concat(anseljson[j]['lightbox']);
- }
-
- // Top level DOM node for this embedded instannce
- var mainNode = $(j);
-
- // Used if we have requested the optional paging feature
- if (anseljson[j]['perpage']) {
- var pagecount = anseljson[j]['perpage'];
- } else {
- var pagecount = anseljson[j]['data'].size();
- }
-
- // For each image in this instance, create the DOM structure
- for (var i = 0; i < pagecount; i++) {
- // Need a nested function and closures to force new scope
- (function() {
- var jx = j;
- var ix = i;
- var imgContainer = new Element('span', {className: 'anselGalleryWidget'});
- if (!anseljson[jx]['hideLinks']) {
- if (anseljson[jx]['linkToGallery']) {
- var idx = 6;
- } else {
- var idx = 5;
- }
- var imgLink = imgContainer.appendChild(new Element('a',
- {
- href: anseljson[jx]['data'][ix][idx],
- title: anseljson[jx]['data'][ix][2]
- }));
- var lb_data = {image: anseljson[jx]['data'][ix][3]};
- imgLink.appendChild(new Element('img', {src: anseljson[jx]['data'][ix][0]}));
- // Attach the lightbox action if we have lightbox data
- if (typeof anseljson[j]['lightbox'] != 'undefined') {
- imgLink.observe('click', function(e) {ansel_lb.start(lb_data.image); e.stop();});
- }
- } else {
- imgContainer.appendChild(new Element('img', {src: anseljson[jx]['data'][ix][0]}));
- // Attach the lightbox action if we have lightbox data
- if (typeof anseljson[j]['lightbox'] != 'undefined') {
- imgLink.observe('click', function(e) {ansel_lb.start(lb_data.image); e.stop();});
- }
- }
-
- mainNode.appendChild(imgContainer);
- })();
- }
-
- if (anseljson[j]['perpage'] > 0) {
- (function() {
- var jx = j;
-
- var nextLink = new Element('a',{href: '#', title: 'Next Image', className: 'anselNext', style: 'text-decoration:none;width:40%;float:right;'});
- nextLink.update('>>');
- var arg1 = {node: jx, page: 1};
- nextLink.observe('click', function(e) {displayPage(e, arg1)});
-
- var prevLink = new Element('a',{href: '#', title: 'Previous Image', className: 'anselPrev', style: 'text-decoration:none;width:40%;float:right;'});
- prevLink.update('<<');
- var arg2 = {node: jx, page: -1};
- prevLink.observe('click', function(e) {displayPage(e, arg2)});
- $(jx).appendChild(nextLink);
- $(jx).appendChild(prevLink);
- Horde_ToolTips.attachBehavior(jx);
- Event.observe(window, 'unload', Horde_ToolTips.out.bind(Horde_ToolTips));
-
- })();
- } else {
- (function () {
- var jx = j;
- Horde_ToolTips.attachBehavior(jx);
- })();
- }
- }
- if (lightboxData.length) {
- lbOptions['gallery_json'] = lightboxData;
- ansel_lb = new Lightbox(lbOptions);
- }
-
- Event.observe(window, 'unload', Horde_ToolTips.out.bind(Horde_ToolTips));
- });
-
-/**
- * Display the images from the requested page for the requested node.
- *
- * @param string $node The DOM id of the embedded widget.
- * @param integer $page The requested page number.
- */
-function displayPage(event, args) {
- var node = args.node;
- var page = args.page;
- var perpage = anseljson[node]['perpage'];
- var imgcount = anseljson[node]['data'].size();
- var pages = Math.ceil(imgcount / perpage) - 1;
- var oldPage = anseljson[node]['page'];
-
- page = oldPage + page;
-
- /* Rollover? */
- if (page > pages) {
- page = 0;
- }
- if (page < 0) {
- page = pages;
- }
-
- var mainNode = $(node);
- mainNode.update();
- var start = page * perpage;
- var end = Math.min(imgcount - 1, start + perpage - 1);
- for (var i = start; i <= end; i++) {
- var imgContainer = mainNode.appendChild(new Element('span', {className: 'anselGalleryWidget'}));
- var imgLink = imgContainer.appendChild(new Element('a',
- {
- href: anseljson[node]['data'][i][5],
- alt: anseljson[node]['data'][i][2],
- title: anseljson[node]['data'][i][2]
- }));
- imgLink.appendChild(new Element('img', {src: anseljson[node]['data'][i][0]}));
- }
-
- var nextLink = new Element('a',{href: '', title: 'Next Image', style: 'text-decoration:none;width:40%;float:right;'});
- nextLink.update('>>');
-
- var args = {node: node, page: ++oldPage};
- nextLink.observe('click', function(e) {displayPage(e, args);}.bind());
-
- var prevLink = new Element('a',{href: '', title: 'Previous Image', style: 'text-decoration:none;width:40%;float:right;'});
- prevLink.update('<<');
-
- var args = {node: node, page: --oldPage};
- prevLink.observe('click', function(e) {displayPage(e, args);}.bind());
-
- mainNode.appendChild(nextLink);
- mainNode.appendChild(prevLink);
-
- Horde_ToolTips.attachBehavior(node);
- anseljson[node]['page'] = page;
- event.stop();
-}
-//]
+++ /dev/null
-/**
- * Google maps implementation for Ansel
- *
- * Copyright 2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael J. Rubinsky <mrubinsk@horde.org>
- */
-var Ansel_GMap = Class.create();
-
-Ansel_GMap.prototype = {
- // Main google map handle
- mainMap: undefined,
-
- // Smaller overview map handle
- smallMap: undefined,
-
- // Tinymarker icons...
- tI: undefined,
- tIO: undefined,
-
- // GLatLngBounds obejct for calculating proper center and zoom
- bounds: undefined,
-
- // Geocoder
- geocoder: undefined,
-
- // MarkerManager, if we are browsing the map.
- // Note we need <script src="http://gmaps-utility-library.googlecode.com/svn/trunk/markermanager/release/src/markermanager.js">
- manager: undefined,
-
- // Can override via options array
- // Pass these in options array as empty string if you do not have them
- // on your view
- tilePrefix: 'imagetile_',
- locationId: 'ansel_locationtext',
- coordId: 'ansel_latlng',
- relocateId: 'ansel_relocate',
- deleteId: 'ansel_deleteGeotag',
- maxZoom: 15,
- defaultZoom: 15,
- options: {},
-
- // Array of GOverlays (GMarker or Ansel_GOverlay objects)
- points: [],
-
- // const'r
- // options.smallMap = [id: 80px];
- // .mainMap [id: xx]
- // .viewType (Gallery, Image, Edit)
- // .relocateUrl base url to the edit/relocate page
- // .relocateText localized text for the relocate link
- // .deleteGeotagText localized text for delete geotag link
- // .deleteGeotagCallback js callback function to be called after
- // deletion is successful
-
- // .clickHandler - optional callback to handle click events on the mainMap
- // .hasEdit - Has PERMS_EDIT on the image
- // .calculateMaxZoom - call Google's getMaxZoomAtLatLng() method to
- // avoid autozooming in to a level with no detail.
- // Performance penalty because we make another
- // round trip to google's service and lately it
- // appears rather slow.
- // .updateEndpoint URL to imple.php
- initialize: function(options) {
- // Use the manager by default.
- if (typeof options.useManager == 'undefined') {
- options.useManager = true;
- }
- this.mainMap = new GMap2($(options.mainMap));
- this.mainMap.setMapType(G_HYBRID_MAP);
- this.mainMap.setUIToDefault();
- this.bounds = new GLatLngBounds();
- this.geocoder = new GClientGeocoder();
- this.options = options;
- if (options.tilePrefix) {
- this.tilePrefix = options.tilePrefix;
- }
-
- if (typeof options.calculateMaxZoom == 'undefined') {
- options.calculateMaxZoom = true;
- }
-
- if (options.smallMap) {
- this.smallMap = new GMap2($(options.smallMap));
- var cUI = this.smallMap.getDefaultUI();
- cUI.controls.menumaptypecontrol = false;
- this.smallMap.setUI(cUI);
-
- // Create our "tiny" marker icon
- // We should copy these locally once this is fleshed out...
- this.tI = new GIcon();
- this.tI.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
- this.tI.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
- this.tI.iconSize = new GSize(12, 20);
- this.tI.shadowSize = new GSize(22, 20);
- this.tI.iconAnchor = new GPoint(6, 20);
- this.tI.infoWindowAnchor = new GPoint(5, 1);
- this.tIO = { icon:this.tI };
- }
-
- // Clean up
- document.observe('unload', function() {GUnload();});
- },
-
- /**
- * Adds a set of points to the map. Each entry in the points array should
- * contain:
- * image_latitude,image_longitude
- * (optional)markerOnly - Don't add thumbnails or event handlers
- *
- * @param array
- * @param minZoom at what minimum zoom level should this set of points be
- * displayed? Ignored if not using the MarkerManager
- */
- addPoints: function(points, minZoom) {
- var l = points.length;
- for (var i = 0; i < l; i++) {
- var ll = new GLatLng(parseFloat(points[i].image_latitude), parseFloat(points[i].image_longitude));
- this.bounds.extend(ll);
- if (points[i].markerOnly == true) {
- // We only support draggable GMarkers, not custom overlays.
- if (points[i].draggable) {
- var mO = {draggable: true};
- var marker = new GMarker(ll, mO);
- GEvent.addListener(marker, "drag", function(ll) {
- $(this.coordId).update(this._point2Deg(ll));
- }.bind(this));
- GEvent.addListener(marker, "dragend", function(ll) {
- this.geocoder.getLocations(ll, function(address) {
- this.getLocationCallback(address, new GMarker(ll));
- }.bind(this));
- }.bind(this));
- } else {
- // This is the single marker for the current image in the image view.
- // Make sure we have a high enough zIndex value for it.
- var marker = new GMarker(ll, {zIndexProcess: function(marker) {return GOverlay.getZIndex(-90);}});
- }
- } else {
- var marker = new anselGOverlay(ll, points[i]);
- }
- // Click handlers only apply to our custom GOverlay.
- if (!points[i].markerOnly && !options.viewType == 'Block') {
- (function() {
- var p = points[i];
- GEvent.addDomListener(marker.div_, 'click', function() {
- a = $$('#' + this.tilePrefix + p.image_id + ' a')[0];
- if (!a.onclick || a.onclick() != false) {
- location.href = a.href;
- }
- }.bind(this));}.bind(this))();
- }
- // extend the GOverlay with our image data too.
- marker.image_data = points[i];
- this.points.push(marker);
-
- // Only put the current image on the small map if we are in the
- // Image view.
- if (this.options.smallMap &&
- (options.viewType != 'Image' || points[i].markerOnly)) {
- var marker2 = new GMarker(ll, this.tIO);
- this.smallMap.addOverlay(marker2);
- }
- }
-
- if (this.options.viewType == 'Gallery' || this.options.viewType == 'Block') {
- if (this.options.calculateMaxZoom) {
- this.mainMap.getCurrentMapType().getMaxZoomAtLatLng(this.bounds.getCenter(), function(response) {
- if (response.status != 200) {
- var zl = Math.min(this.mainMap.getBoundsZoomLevel(this.bounds) - 1, this.maxZoom);
- } else {
- var zl = Math.min(this.mainMap.getBoundsZoomLevel(this.bounds) - 1, Math.min(this.maxZoom, response.zoom - 1));
- }
- this._mapSetCenter(zl);
- this._managerSetup(minZoom);
- }.bind(this));
- } else {
- this._mapSetCenter(Math.min(this.mainMap.getBoundsZoomLevel(this.bounds) - 1, this.maxZoom));
- this._managerSetup(minZoom);
- }
- } else {
- // Not a Gallery View...
- this.mainMap.setCenter(this.points[0].getLatLng(), Math.min(this.mainMap.getBoundsZoomLevel(this.bounds) - 1, this.maxZoom));
- // Can't instantiate a manager until after the GMap2 has had
- // setCenter() called, so we can't do this in the const'r
- if (this.options.useManager && this.manager == null) {
- this.manager = new MarkerManager(this.mainMap);
- }
- if (this.options.useManager) {
- if (minZoom == null) {
- minZoom = 0;
- }
- this.manager.addMarkers(this.points, minZoom);
- this.manager.refresh();
- }
- if (this.options.smallMap) {
- this.smallMap.setCenter(this.mainMap.getCenter(), 1);
- }
- }
- },
-
- /**
- * Helper method to set the map center and refresh the MarkerManager
- * if we are using one.
- *
- * @param integer zl The zoom level to set the map at once it's centered.
- * @param integer mz The minimum zoom level needed to display the currently
- * added points if using the MarkerManager.
- */
- _mapSetCenter: function(zl, mz) {
- this.mainMap.setCenter(this.bounds.getCenter(), zl);
- if (this.options.smallMap) {
- this.smallMap.setCenter(this.mainMap.getCenter(), 1);
- }
- },
-
- _managerSetup: function(mz) {
- // Can't instantiate a manager until after the GMap2 has had
- // setCenter() called, so we *must* do this here.
- if (this.options.useManager && this.manager == null) {
- this.manager = new MarkerManager(this.mainMap);
- }
- if (this.options.useManager) {
- if (mz == null) {
- mz = 0;
- }
- this.manager.addMarkers(this.points, mz);
- this.manager.refresh();
- }
- },
-
- /**
- * Display all points on the map. If we are using the MarkerManager, then
- * this function only obtains the reverse geocode data and (via the callback)
- * adds the event handlers to display the geocode data. If we aren't using
- * the manager, this also adds the overlay to the map.
- */
- display: function() {
- var l = this.points.length;
- for (var i = 0; i < l; i++) {
- // Force closure on p
- (function() {
- var p = this.points[i];
- if (!this.options.useManager) {
- this.mainMap.addOverlay(p);
- }
- // For now, only do this on the current Image in the image view
- // or for all images in Gallery view.
- if ((this.options.viewType != 'Block' && this.options.viewType != 'Image') || p.image_data.markerOnly) {
- this.getLocations(p);
- }
- }.bind(this))();
- }
-
- if (this.options.clickHandler) {
- GEvent.addListener(this.mainMap, "click", this.options.clickHandler);
- }
- },
-
- /**
- * Custom getLocations method so we can check for our own locally cached
- * geodata first. We can't implement our own GGeocodeCache becuase we want
- * to allow a per-user override of an individual image, not a general cache
- * of lat/lng => location text.
- */
- getLocations: function(p) {
- if (p.image_data.image_location.length > 0) {
- r = {Status: {code: 200}, Placemark: [{AddressDetails: {Accuracy: 4}, address:p.image_data.image_location}], NoUpdate: true};
- this.getLocationCallback(r, p, false);
- } else {
- this.geocoder.getLocations(p.getLatLng(), function(address) {this.getLocationCallback(address, p, true)}.bind(this));
- }
- },
-
- /**
- * Callback to parse and attach location data the the points on the map.
- * Adds event handlers to display the location data on mouseover. Also
- * highlights the image tile (since these would only be called in gallery
- * view) - need to use a seperate handler for that once we start storing
- * reverse geocode data locally.
- *
- * @TODO: Is it worth the effort to define the callback in the page that
- * is calling this to make this more OO-like? Maybe for H4 when I
- * try to make this a more generic Google library??
- *
- */
- getLocationCallback: function(points, marker, update) {
- if (typeof update == 'undefined') { update = false;}
- if (points.Status.code != 200) {
- // Fake the data so we can at least update what we have
- points.Placemark = [{AddressDetails: {Accuracy: 0}, address: ''}];
- update = false;
- }
-
- if (marker.image_data) {
- var image_data = marker.image_data;
- } else {
- image_data = {};
- }
-
- for (var i = 0; i < points.Placemark.length; i++) {
- var place = points.Placemark[i];
- if (place.AddressDetails.Accuracy <= 4) {
- // These events handlers should only be fired on the Gallery
- // view for our special GOverlay objects (which already have
- // a mouseover/out handler to focus them).
- if (!image_data.markerOnly && this.options.viewType == 'Gallery' && this.locationId) {
- GEvent.addDomListener(marker.div_, 'mouseover', function() {
- $(this.locationId).update(place.address);
- $$('#' + this.tilePrefix + image_data.image_id + ' img')[0].toggleClassName('image-tile-highlight');
- }.bind(this));
- GEvent.addDomListener(marker.div_, 'mouseout', function() {
- $(this.locationId).update('<br />');
- $$('#' + this.tilePrefix + image_data.image_id + ' img')[0].toggleClassName('image-tile-highlight');
- }.bind(this));
- }
-
- // Cache the location locally?
- if (update) {
- new Ajax.Request(this.options['updateEndpoint'],
- {
- method: 'post',
- parameters: {
- type: 'location',
- location: encodeURIComponent(place.address),
- img: image_data.image_id
- }
- }
- );
- }
- // These handlers are for the image tiles themselves in the
- // Gallery view - to highlight our GOverlays on the map.
- if (this.options.viewType == 'Gallery') {
- if (this.locationId) {
- $$('#' + this.tilePrefix + image_data.image_id + ' img')[0].observe('mouseover', function() {
- $(this.locationId).update(place.address);
- $$('#' + this.tilePrefix + image_data.image_id + ' img')[0].toggleClassName('image-tile-highlight');
- marker.focus();
- }.bind(this));
- $$('#' + this.tilePrefix + image_data.image_id + ' img')[0].observe('mouseout', function() {
- $(this.locationId).update('<br />');
- $$('#' + this.tilePrefix + image_data.image_id + ' img')[0].toggleClassName('image-tile-highlight');
- marker.div_.style.border = '1px solid white';
- marker.focus();
- }.bind(this));
- }
-
- return;
- } else if (this.options.viewType == 'Image') {
- // If Image view and this is the markerOnly point.
- if (image_data.markerOnly) {
- if (this.locationId) {
- $(this.locationId).update(place.address);
- }
- if (this.coordId) {
- $(this.coordId).update(this._point2Deg(marker.getLatLng()));
- }
- if (this.relocateId) {
- $(this.relocateId).update(this._getRelocateLink(image_data.image_id));
- }
-
- if (this.deleteId) {
- $(this.deleteId).update(this._getDeleteLink(image_data.image_id));
- }
- }
-
- return;
- } else {
- // Edit view
- $(this.locationId).update(place.address);
- $(this.coordId).update(this._point2Deg(marker.getLatLng()));
-
- return;
- }
-
- } else {
- // Parse less detail, or just move on to the next hit??
- }
- }
- },
-
- _point2Deg: function(ll) {
- function dec2deg(dec, lat)
- {
- var letter = lat ? (dec > 0 ? "N" : "S") : (dec > 0 ? "E" : "W");
- dec = Math.abs(dec);
- var deg = Math.floor(dec);
- var min = Math.floor((dec - deg) * 60);
- var sec = (dec - deg - min / 60) * 3600;
- return deg + "° " + min + "' " + sec.toFixed(2) + "\" " + letter;
- }
-
- return dec2deg(ll.lat(), true) + " " + dec2deg(ll.lng());
- },
-
- _getRelocateLink: function(iid) {
- if (options.hasEdit) {
- var a = new Element('a', {href: this.options.relocateUrl + '?image=' + iid}).update(this.options.relocateText);
- a.observe('click', function(e) { Horde.popup({ url: this.options.relocateUrl, params: 'image=' + iid, width: 750, height: 600 }); e.stop();}.bind(this));
- return a;
- } else {
- return '';
- }
- },
-
- _getDeleteLink: function(iid) {
- var x = new Element('a', {href: this.options.relocateUrl + '?image=' + iid}).update(this.options.deleteGeotagText);
- x.observe('click', function(e) {this.options.deleteGeotagCallback(); e.stop();}.bindAsEventListener(this));
- return x;
- }
-
-}
-
-/**
- * Define our custom GOverlay to display thumbnails of images on the map.
- * Use an Image object to get the exact dimensions of the image. Need this
- * wrapped in an onload handler to be sure GOverlay() is defined.
- */
-anselGOverlay = function(latlng, image_data) {
- this.src_ = image_data.icon;
- this.latlng_ = latlng;
- var img = new Image();
- img.src = image_data.icon;
- this.width_ = img.width;
- this.height_ = img.height;
- var z = GOverlay.getZIndex(this.latlng_.lat());
- this.div_ = new Element('div', {style: 'position:absolute;border:1px solid white;width:' + (this.width_ - 2) + 'px; height:' + (this.height_ - 2) + 'px;zIndex:' + z});
- this.img_ = new Element('img', {src: this.src_, style: 'width:' + (this.width_ - 2) + 'px;height:' + (this.height_ - 2) + 'px'});
- this.div_.appendChild(this.img_);
- this.selected_ = false;
- this.link = image_data.link;
-
- // Handlers to hightlight the node for this overlay on mouseover/out
- GEvent.addDomListener(this.div_, 'mouseover', function() {
- this.focus();
- }.bind(this));
- GEvent.addDomListener(this.div_, 'mouseout', function() {
- this.focus();
- }.bind(this));
-
- // Add a click handler to navigate to the image view for this image.
- if (this.link) {
- GEvent.addDomListener(this.div_, 'click', function() {
- var a = this.link;
- location.href = a;
- }.bind(this));
- }
- };
-
- anselGOverlay.prototype = new GOverlay();
- anselGOverlay.prototype.initialize = function(map) {
- map.getPane(G_MAP_MARKER_PANE).appendChild(this.div_);
- this.map_ = map;
- };
-
- //Remove the main DIV from the map pane
- // TODO: We should unregister the event handlers adding in initialize()
- anselGOverlay.prototype.remove = function() {
- this.div_.parentNode.removeChild(this.div_);
- };
-
- // Copy our data to a new GOverlay
- anselGOverlay.prototype.copy = function() {
- return new Ansel_GOverlay(this.latlng_, this.src_);
- };
-
- anselGOverlay.prototype.redraw = function(force) {
- // We only need to redraw if the coordinate system has changed
- if (!force) return;
- var coords = this.map_.fromLatLngToDivPixel(this.latlng_);
- this.div_.style.left = coords.x + "px";
- this.div_.style.top = coords.y + "px";
-};
-
-anselGOverlay.prototype.focus = function()
-{
- if (this.selected_ == false) {
- this.div_.style.border = '1px solid red';
- this.div_.style.left = (parseInt(this.div_.style.left) - 1) + "px";
- this.div_.style.top = (parseInt(this.div_.style.top) - 1) + "px";
- this.div_.style.zIndex = GOverlay.getZIndex(-90.0);
- this.selected_ = true;
- } else {
- this.div_.style.border = '1px solid white';
- this.div_.style.left = (parseInt(this.div_.style.left) + 1) + "px";
- this.div_.style.top = (parseInt(this.div_.style.top) + 1) + "px";
- this.div_.style.zIndex = GOverlay.getZIndex(this.latlng_.lat());
- this.selected_ = false;
- }
-};
-
-// MarkerManager seems to be incosistent with the methods it calls to get
-// the GLatLng for each overlay. addMarkers() seems to need the deprecated
-// getPoint() while addMarker() uses the newer getLatLng() mehtod.
-anselGOverlay.prototype.getPoint = function() {
- return this.latlng_;
-}
-anselGOverlay.prototype.getLatLng = function() {
- return this.latlng_;
-}
+++ /dev/null
-/**
- * Javascript specific for the adding/moving a geotag via the map_edit.php page
- *
- * Copyright 2009 The Horde Project (http://www.horde.org)
- *
- * @author Michael J. Rubinsky
- * @package Ansel
- */
-
-/**
- * Ansel_MapEdit class encapsulates various functions for searching/setting
- * locations.
- *
- * mapEdit = new Ansel_MapEdit(options)
- *
- * options is an object with the following required properties:
- *
- * mainMap - DOM id for the google map
- * image_id - The image_id for the Ansel_Image we are tagging.
- * gettext - Various gettext strings (fetching, errortext)
- * xurl - The URL for imple.php
- *
- * and some optional properties:
- *
- * statusId - DOM id for a status message
- * locationInput - DOM id for the location search input field
- * locationAction - DOM id for the Find button
- * isNew - Set to 1 if image is a newly geotagged image, 0 if we are
- * moving an existing geotag.
- *
- *
- */
-Ansel_MapEdit = Class.create();
-Ansel_MapEdit.prototype = {
-
- _options: null,
- _map: null,
-
- // {image_latitude: image_longitude:}
- ll: null,
-
- initialize: function(options)
- {
- this._options = Object.extend({
- statusId: 'status',
- locationInput: 'locationInput',
- locationAction: 'locationAction',
- isNew: '0'
- }, options);
-
- this._map = new Ansel_GMap({mainMap: this._options.mainMap,
- viewType: 'Edit',
- useManager: false,
- clickHandler: function(ol, ll, olll) {
- this._map.points[0].setLatLng(ll);
- this._map.points[0].image_data = {image_location: '',
- image_latitude: ll.lat(),
- image_longitude: ll.lng()};
- this._map.getLocations(this._map.points[0]);
- }.bind(this)});
- if (this._options.isNew) {
- this._map.maxZoom = 1;
- }
-
- this._map._getLocationCallback = this._map.getLocationCallback;
- this._map.getLocationCallback = function(points, marker) {
- this._map._getLocationCallback(points, marker);
- }.bind(this);
-
- this._map.addPoints(this._options.points);
- this._map.display();
- $(this._options.locationAction).observe('click', function(e) {this.getLocation();e.stop();}.bindAsEventListener(this));
- $(this._options.saveId).observe('click', function() {this.handleSave(this._options.image_id);}.bind(this));
- },
-
- handleSave: function(id)
- {
- var o = this._options;
- params = {
- img: id,
- lat: this._map.points[0].getLatLng().lat(),
- lng: this._map.points[0].getLatLng().lng(),
- type: 'geotag'
- };
- //url = this._options.url;
- new Ajax.Request(o.xurl, {
- method: 'post',
- parameters: params,
- onComplete: function(transport) {
- if (transport.responseJSON.response > 0) {
- window.opener.location.href = window.opener.location.href;
- window.close();
- } // what to do if failure?
- }
- });
- },
-
- getLocation: function()
- {
- var o = this._options;
-
- $(this._options.statusId).update(this._options.gettext.fetching);
- if (this.ll) {
- //already have lat/lng from the autocompleter
- var gll = new GLatLng(this.ll.image_latitude, this.ll.image_longitude);
- this._map.points[0].setLatLng(gll);
- this._map.points[0].image_data = {image_location: $F(o.locationInput),
- image_latitude: gll.lat(),
- image_longitude: gll.lng()};
-
- this._map.getLocations(this._map.points[0]);
- this._map.mainMap.setCenter(gll, this._map.defaultZoom);
- $(o.statusId).update('');
- } else {
- this._map.geocoder.getLocations($(o.locationInput).value, function(address) {
- if (address.Status.code == '200') {
- // For now, just try the first returned spot - not sure how else to handle this
- var lat = address.Placemark[0].Point.coordinates[1];
- var lng = address.Placemark[0].Point.coordinates[0];
- var gll = new GLatLng(lat, lng);
- this._map.points[0].setLatLng(gll);
- this._map.points[0].image_data = {image_location: '',
- image_latitude: lat,
- image_longitude: lng};
-
- this._map.getLocations(this._map.points[0]);
- this._map.mainMap.setCenter(gll, this._map.defaultZoom);
- $(o.statusId).update('');
- } else {
- $(o.statusId).update(o.gettext.errortext + address.Status.code);
- }
- }.bind(this));
- }
- },
-
- setLocation: function(lat, lng, loc)
- {
- var gll = new GLatLng(lat, lng);
- this._map.points[0].setLatLng(gll);
- this._map.points[0].image_data = {image_location: loc,
- image_latitude: lat,
- image_longitude: lng};
-
- this._map.getLocations(this._map.points[0]);
- this._map.mainMap.setCenter(gll, this._map.defaultZoom);
- }
-
-}
-
-/**
- * Override the Ajax.Autocompleter#updateChoices method so we can handle
- * receiving lat/lng points bound to the location.
- */
-Ajax.Autocompleter.prototype.updateChoices = function(choices) {
- var li, re, ul,
- i = 0;
- this.geocache = choices;
- var hc = $H(choices);
- if (!this.changed && this.hasFocus) {
- li = new Element('LI');
- ul = new Element('UL');
- re = new RegExp("(" + this.getToken() + ")", "i");
- var k = hc.keys();
- k.each(function(n) {
- ul.insert(li.cloneNode(false).writeAttribute('acIndex', i++).update(n.gsub(re, '<strong>#{1}</strong>')));
- });
-
- this.update.update(ul);
-
- this.entryCount = k.size();
- ul.childElements().each(this.addObservers.bind(this));
-
- this.stopIndicator();
- this.index = 0;
-
- if (this.entryCount == 1 && this.options.autoSelect) {
- this.selectEntry();
- } else {
- this.render();
- }
- }
-
- if (this.options.afterUpdateChoices) {
- this.options.afterUpdateChoices(hc, ul);
- }
-}
-
-/**
- * Override the Autocompler.Local#initialize method to take an Object instead
- * of an Array, and set the appropriate properties.
- */
-Autocompleter.Local.prototype.initialize = function(element, update, obj, options) {
- this.baseInitialize(element, update, options);
- this.geocache = obj;
- this.options.arr = $H(obj).keys();
-}
+++ /dev/null
-function showFace(id)
-{
- $('facediv' + id).addClassName('shown');
- $('facethumb' + id).style.border = '1px solid red';
- $('facedivname' + id).style.display = 'inline';
-}
-function hideFace(id)
-{
- $('facediv' + id).removeClassName('shown');
- $('facethumb' + id).style.border = '1px solid black';
- $('facedivname' + id).style.display = 'none';
-}
-document.observe('dom:loaded', function() {
- Event.observe($('photodiv'), 'load', function() {
- $('faces-on-image').immediateDescendants().collect(function(element) {
- element.clonePosition($('photodiv'), {setWidth: false, setHeight: false});
- });
- });
-});
+++ /dev/null
-// This file modified in various ways for use in Ansel. Mostly to allow
-// the lightbox images to span multiple gallery pages...and thus is no longer
-// really "Lightbox", but a good bit of the original code is still intact.
-// The original credits/copyright appears below.
-
-// -----------------------------------------------------------------------------------
-//
-// Lightbox v2.04
-// by Lokesh Dhakar - http://www.lokeshdhakar.com
-// Last Modification: 2/9/08
-//
-// For more information, visit:
-// http://lokeshdhakar.com/projects/lightbox2/
-//
-// Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
-// - Free for use in both personal and commercial projects
-// - Attribution requires leaving author name, author link, and the license info intact.
-//
-// Thanks: Scott Upton(uptonic.com), Peter-Paul Koch(quirksmode.com), and Thomas Fuchs(mir.aculo.us) for ideas, libs, and snippets.
-// Artemy Tregubenko (arty.name) for cleanup and help in updating to latest ver of proto-aculous.
-//
-// -----------------------------------------------------------------------------------
-/*
-
- Table of Contents
- -----------------
- Configuration
-
- Lightbox Class Declaration
- - initialize()
- - updateImageList()
- - start()
- - changeImage()
- - resizeImageContainer()
- - showImage()
- - updateDetails()
- - updateNav()
- - enableKeyboardNav()
- - disableKeyboardNav()
- - keyboardAction()
- - preloadNeighborImages()
- - end()
-
- Function Calls
- - document.observe()
-
-*/
-// -----------------------------------------------------------------------------------
-
-var Lightbox = Class.create();
-
-Lightbox.prototype = {
- imageArray: [],
- activeImage: undefined,
- options: undefined,
-
- // initialize()
- // Constructor runs on completion of the DOM loading. Calls updateImageList and then
- // the function inserts html at the bottom of the page which is used to display the shadow
- // overlay and the image container.
- //
- // Modified 3/25/2008 Michael J. Rubinsky <mrubinsk@horde.org> to remove
- // dependency on scriptaculous' Builder object since the new Element
- // constructor in Prototype does this more efficently.
- initialize: function(options) {
-
- this.options = options;
- this.imageArray = this.options.gallery_json;
- this.keyboardAction = this.keyboardAction.bindAsEventListener(this);
- if (this.options.resizeSpeed > 10) this.options.resizeSpeed = 10;
- if (this.options.resizeSpeed < 1) this.options.resizeSpeed = 1;
- this.resizeDuration = this.options.animate ? ((11 - this.options.resizeSpeed) * 0.15) : 0;
- this.overlayDuration = this.options.animate ? 0.2 : 0; // shadow fade in/out duration
-
- // When Lightbox starts it will resize itself from 250 by 250 to the current image dimension.
- // If animations are turned off, it will be hidden as to prevent a flicker of a
- // white 250 by 250 box.
-
- var size = (this.options.animate ? 250 : 1) + 'px';
-
- // Code inserts html at the bottom of the page that looks similar to this:
- //
- // <div id="overlay"></div>
- // <div id="lightbox">
- // <div id="outerImageContainer">
- // <div id="imageContainer">
- // <img id="lightboxImage">
- // <div style="" id="hoverNav">
- // <a href="#" id="prevLink"></a>
- // <a href="#" id="nextLink"></a>
- // </div>
- // <div id="loading">
- // <a href="#" id="loadingLink">
- // <img src="images/loading.gif">
- // </a>
- // </div>
- // </div>
- // </div>
- // <div id="imageDataContainer">
- // <div id="imageData">
- // <div id="imageDetails">
- // <span id="caption"></span>
- // <span id="numberDisplay"></span>
- // </div>
- // <div id="bottomNav">
- // <a href="#" id="bottomNavClose">
- // <img src="images/close.gif">
- // </a>
- // </div>
- // </div>
- // </div>
- // </div>
-
-
- var objBody = $$('body')[0];
-
- objBody.appendChild(new Element('div', {id: 'overlay'}));
-
- // Build innermost children
- var hoverNav = new Element('div', {id: 'hoverNav'});
- hoverNav.appendChild(new Element('a', {id:'prevLink', href: '#'}));
- hoverNav.appendChild(new Element('a', {id: 'nextLink', href: '#'}));
-
- var loadingLink = new Element('a', {id: 'loadingLink', href: '#'});
- loadingLink.appendChild(new Element('img', {src: this.options.fileLoadingImage}));
-
- var loading = new Element('div', {id: 'loading'});
- loading.appendChild(loadingLink);
-
- var container = new Element('div', {id: 'imageContainer'});
- container.appendChild(new Element('img', {id: 'lightboxImage'}));
- container.appendChild(hoverNav);
- container.appendChild(loading);
-
- var outerContainer = new Element('div', {id: 'outerImageContainer'});
- outerContainer.appendChild(container);
-
- var imageDetails = new Element('div', {id: 'imageDetails'});
- imageDetails.appendChild(new Element('span', {id: 'caption'}));
- imageDetails.appendChild(new Element('span', {id: 'numberDisplay'}));
-
- var bottomClose = new Element('a', {id: 'bottomNavClose', href: '#'});
- bottomClose.appendChild(new Element('img', {src: this.options.fileBottomNavCloseImage}));
-
- var bottomNav = new Element('div', {id: 'bottomNav'});
- bottomNav.appendChild(bottomClose);
-
- var imageData = new Element('div', {id: 'imageData'});
- imageData.appendChild(imageDetails);
- imageData.appendChild(bottomNav);
-
- var imageDataContainer = new Element('div', {id: 'imageDataContainer'});
- imageDataContainer.appendChild(imageData);
-
- // The outermost node
- var lightbox = new Element('div', {id: 'lightbox'});
- lightbox.appendChild(outerContainer);
- lightbox.appendChild(imageDataContainer);
-
- objBody.appendChild(lightbox);
-
- $('overlay').hide().observe('click', (function() { this.end(); }).bind(this));
- $('lightbox').hide().observe('click', (function(event) { if (event.element().id == 'lightbox') this.end(); }).bind(this));
- $('outerImageContainer').setStyle({ width: size, height: size });
-
- // Need to cache the event listener function so we can call stopObserving() later
- this.prevEventListener = (function(event) { event.stop(); this.changeImage(this.activeImage - 1); }).bindAsEventListener(this);
- $('prevLink').observe('click', this.prevEventListener);
-
- this.nextEventListener = (function(event) { event.stop(); this.changeImage(this.activeImage + 1); }).bindAsEventListener(this);
- $('nextLink').observe('click', this.nextEventListener);
- $('loadingLink').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
- $('bottomNavClose').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
- },
-
- //
- // start()
- // Display overlay and lightbox.
- //
- start: function(imageId) {
-
- $$('select', 'object', 'embed').invoke('setStyle', 'visibility:hidden');
-
- // stretch overlay to fill page and fade in
- var arrayPageSize = this.getPageSize();
- $('overlay').setStyle({ height: arrayPageSize[1] + 'px' });
-
- new Effect.Appear($('overlay'), { duration: this.overlayDuration, from: 0.0, to: this.options.overlayOpacity });
-
- // calculate top and left offset for the lightbox
- var arrayPageScroll = document.viewport.getScrollOffsets();
- var lightboxTop = arrayPageScroll[1] + (document.viewport.getHeight() / 15);
- var lightboxLeft = arrayPageScroll[0];
- $('lightbox').setStyle({ top: lightboxTop + 'px', left: lightboxLeft + 'px' }).show();
-
- // Need to find the index for this image.
- var imageNum = 0;
- while (this.imageArray[imageNum][3] != imageId || imageNum > this.imageArray.length - 1) {
- imageNum++;
- }
-
- this.changeImage(imageNum);
- return false;
- },
-
- //
- // changeImage()
- // Hide most elements and preload image in preparation for resizing image container.
- //
- changeImage: function(imageNum) {
- this.activeImage = imageNum; // update global var
-
- // hide elements during transition
- if (this.options.animate) $('loading').show();
- $('lightboxImage', 'hoverNav', 'prevLink', 'nextLink', 'numberDisplay').invoke('hide');
- // HACK: Opera9 does not currently support scriptaculous opacity and appear fx
- $('imageDataContainer').setStyle({opacity: .0001});
-
- var imgPreloader = new Image();
-
- // once image is preloaded, resize image container
- imgPreloader.onload = (function(){
- $('lightboxImage').src = this.imageArray[this.activeImage][0];
- this.resizeImageContainer(imgPreloader.width, imgPreloader.height);
- }).bind(this);
- imgPreloader.src = this.imageArray[this.activeImage][0];
- },
-
- //
- // resizeImageContainer()
- //
- resizeImageContainer: function(imgWidth, imgHeight) {
-
- // get current width and height
- var widthCurrent = $('outerImageContainer').getWidth();
- var heightCurrent = $('outerImageContainer').getHeight();
-
- // get new width and height
- var widthNew = (imgWidth + this.options.borderSize * 2);
- var heightNew = (imgHeight + this.options.borderSize * 2);
-
- // scalars based on change from old to new
- var xScale = (widthNew / widthCurrent) * 100;
- var yScale = (heightNew / heightCurrent) * 100;
-
- // calculate size difference between new and old image, and resize if necessary
- var wDiff = widthCurrent - widthNew;
- var hDiff = heightCurrent - heightNew;
-
- if (hDiff != 0) new Effect.Scale($('outerImageContainer'), yScale, {scaleX: false, duration: this.resizeDuration, queue: 'front'});
- if (wDiff != 0) new Effect.Scale($('outerImageContainer'), xScale, {scaleY: false, duration: this.resizeDuration, delay: this.resizeDuration});
-
- // if new and old image are same size and no scaling transition is necessary,
- // do a quick pause to prevent image flicker.
- var timeout = 0;
- if ((hDiff == 0) && (wDiff == 0)){
- timeout = 100;
- if (Prototype.Browser.IE) timeout = 250;
- }
-
- (function(){
- $('prevLink', 'nextLink').invoke('setStyle', 'height:' + imgHeight + 'px');
- $('imageDataContainer').setStyle({ width: widthNew + 'px' });
- this.showImage();
- }).bind(this).delay(timeout / 1000);
- },
-
- //
- // showImage()
- // Display image and begin preloading neighbors.
- //
- showImage: function(){
- $('loading').hide();
- new Effect.Appear($('lightboxImage'), {
- duration: this.resizeDuration,
- queue: 'end',
- afterFinish: (function(){ this.updateDetails(); }).bind(this)
- });
- this.preloadNeighborImages();
- },
-
- //
- // updateDetails()
- // Display caption, image number, and bottom nav.
- //
- updateDetails: function() {
-
- // use caption, or fall back to the file name if it's empty.
- if (this.imageArray[this.activeImage][2] != ""){
- $('caption').update(this.imageArray[this.activeImage][2]).show();
- } else {
- $('caption').update(this.imageArray[this.activeImage][1]).show();
- }
-
- // if image is part of set display 'Image x of x'
- if (this.imageArray.length > 1){
- $('numberDisplay').update( this.options.labelImage + ' ' + (this.activeImage + 1) + ' ' + this.options.labelOf + ' ' + this.imageArray.length).show();
- }
-
- new Effect.Parallel(
- [
- new Effect.SlideDown($('imageDataContainer'), { sync: true, duration: this.resizeDuration, from: 0.0, to: 1.0 }),
- new Effect.Appear($('imageDataContainer'), { sync: true, duration: this.resizeDuration })
- ],
- {
- duration: this.resizeDuration,
- afterFinish: (function() {
- // update overlay size and update nav
- var arrayPageSize = this.getPageSize();
- $('overlay').setStyle({ height: arrayPageSize[1] + 'px' });
- this.updateNav();
- }).bind(this)
- }
- );
- },
-
- //
- // updateNav()
- // Display appropriate previous and next hover navigation.
- //
- updateNav: function() {
-
- $('hoverNav').show();
- // if not first image in set, display prev image button
- if (this.activeImage > 0) $('prevLink').show();
-
- // if not last image in set, display next image button
- if (this.activeImage < (this.imageArray.length - 1)) $('nextLink').show();
-
- this.enableKeyboardNav();
- },
-
- //
- // enableKeyboardNav()
- //
- enableKeyboardNav: function() {
- document.observe('keydown', this.keyboardAction);
- },
-
- //
- // disableKeyboardNav()
- //
- disableKeyboardNav: function() {
- document.stopObserving('keydown', this.keyboardAction);
- },
-
- //
- // keyboardAction()
- //
- keyboardAction: function(event) {
- var keycode = event.keyCode;
-
- var escapeKey;
- if (event.DOM_VK_ESCAPE) { // mozilla
- escapeKey = event.DOM_VK_ESCAPE;
- } else { // ie
- escapeKey = 27;
- }
-
- var key = String.fromCharCode(keycode).toLowerCase();
-
- if (key.match(/x|o|c/) || (keycode == escapeKey)){ // close lightbox
- this.end();
- } else if ((key == 'p') || (keycode == 37)){ // display previous image
- if (this.activeImage != 0){
- this.disableKeyboardNav();
- this.changeImage(this.activeImage - 1);
- }
- } else if ((key == 'n') || (keycode == 39)){ // display next image
- if (this.activeImage != (this.imageArray.length - 1)){
- this.disableKeyboardNav();
- this.changeImage(this.activeImage + 1);
- }
- }
- },
-
- //
- // preloadNeighborImages()
- // Preload previous and next images.
- //
- preloadNeighborImages: function(){
- var preloadNextImage, preloadPrevImage;
- if (this.imageArray.length > this.activeImage + 1){
- preloadNextImage = new Image();
- preloadNextImage.src = this.imageArray[this.activeImage + 1][0];
- }
- if (this.activeImage > 0){
- preloadPrevImage = new Image();
- preloadPrevImage.src = this.imageArray[this.activeImage - 1][0];
- }
-
- },
-
- //
- // end()
- //
- end: function() {
- this.disableKeyboardNav();
- $('lightbox').hide();
- new Effect.Fade($('overlay'), { duration: this.overlayDuration });
- $$('select', 'object', 'embed').invoke('setStyle', 'visibility:visible');
-
- //redirect here//
- if (this.options.startPage != this.imageArray[this.activeImage][4]) {
- location.href = this.options.returnURL + "page=" + this.imageArray[this.activeImage][4];
- }
- },
-
- //
- // getPageSize()
- //
- getPageSize: function() {
-
- var xScroll, yScroll;
-
- if (window.innerHeight && window.scrollMaxY) {
- xScroll = window.innerWidth + window.scrollMaxX;
- yScroll = window.innerHeight + window.scrollMaxY;
- } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
- xScroll = document.body.scrollWidth;
- yScroll = document.body.scrollHeight;
- } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
- xScroll = document.body.offsetWidth;
- yScroll = document.body.offsetHeight;
- }
-
- var windowWidth, windowHeight;
-
- if (self.innerHeight) { // all except Explorer
- if(document.documentElement.clientWidth){
- windowWidth = document.documentElement.clientWidth;
- } else {
- windowWidth = self.innerWidth;
- }
- windowHeight = self.innerHeight;
- } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
- windowWidth = document.documentElement.clientWidth;
- windowHeight = document.documentElement.clientHeight;
- } else if (document.body) { // other Explorers
- windowWidth = document.body.clientWidth;
- windowHeight = document.body.clientHeight;
- }
-
- // for small pages with total height less then height of the viewport
- if(yScroll < windowHeight){
- pageHeight = windowHeight;
- } else {
- pageHeight = yScroll;
- }
-
- // for small pages with total width less then width of the viewport
- if(xScroll < windowWidth){
- pageWidth = xScroll;
- } else {
- pageWidth = windowWidth;
- }
-
- return [pageWidth,pageHeight];
- }
-}
\ No newline at end of file
+++ /dev/null
-/**
- * You can only have one SlideController on a page.
- */
-var SlideController = {
-
- photos: null,
- photoId: 0,
-
- slide: null,
-
- interval: null,
- intervalSeconds: 5,
-
- /**
- * CSS border size x 2
- */
- borderSize: 0,
-
- /**
- * So we can update the links
- */
- baseUrl: null,
- galleryId: 0,
- galleryShare: 0,
- playing: false,
- interval: null,
- tempImage: new Image(),
-
- /**
- * Initialization.
- */
- initialize: function(photos, start, baseUrl, galleryId, galleryShare) {
- SlideController.photoId = start || 0;
- SlideController.baseUrl = baseUrl;
- SlideController.galleryId = galleryId;
- SlideController.galleryShare = galleryShare;
-
- Event.observe(window, 'load', function() {
- Event.observe(SlideController.tempImage, 'load', function() {
- SlideController.photo.initSwap();
- });
- Event.observe($('Photo'), 'load', function() {
- SlideController.photo.showPhoto();
- });
-
- SlideController.photos = photos;
- SlideController.photo = new Slide(SlideController.photoId);
- SlideController.photo.initSwap();
- SlideController.play();
-
- });
- },
-
- /**
- */
- play: function() {
- Element.hide('ssPlay');
- Element.show('ssPause');
- // This sets the first interval for the currently displayed image.
- if (SlideController.interval) {
- clearTimeout(SlideController.interval);
- }
- SlideController.interval = setTimeout(SlideController.next, SlideController.intervalSeconds * 1000);
- SlideController.playing = true;
- },
-
- /**
- */
- pause: function() {
- Element.hide('ssPause');
- Element.show('ssPlay');
- if (SlideController.interval) {
- clearTimeout(SlideController.interval);
- }
- SlideController.playing = false;
- },
-
- /**
- */
- prev: function() {
- SlideController.photo.prevPhoto();
- },
-
- /**
- */
- next: function() {
- SlideController.photo.nextPhoto();
- }
-
-}
-
-// -----------------------------------------------------------------------------------
-//
-// This page coded by Scott Upton
-// http://www.uptonic.com | http://www.couloir.org
-//
-// This work is licensed under a Creative Commons License
-// Attribution-ShareAlike 2.0
-// http://creativecommons.org/licenses/by-sa/2.0/
-//
-// Associated APIs copyright their respective owners
-//
-// -----------------------------------------------------------------------------------
-// --- version date: 11/28/05 --------------------------------------------------------
-//
-// Various changes for properly updating image links, image comments etc...
-// added 4/07 by Michael Rubinsky <mrubinsk@horde.org>
-
-/**
- * Additional methods for Element added by SU, Couloir.
- */
-Object.extend(Element, {
- getWidth: function(element) {
- element = $(element);
- return element.offsetWidth;
- },
- setWidth: function(element,w) {
- element = $(element);
- element.style.width = w + 'px';
- },
- setSrc: function(element,src) {
- element = $(element);
- element.src = src;
- },
- setHref: function(element,href) {
- element = $(element);
- element.href = href;
- },
- setInnerHTML: function(element,content) {
- element = $(element);
- element.innerHTML = content;
- },
- setOnClick: function(element,action) {
- element = $(element);
- element.onclick = action;
- }
-});
-
-var Slide = Class.create();
-Slide.prototype = {
- initialize: function(photoId) {
- this.photoId = photoId;
- this.photo = 'Photo';
- this.captionBox = 'CaptionContainer';
- this.caption = 'Caption';
- },
- setNewPhotoParams: function() {
- // Set source of new image.
- Element.setSrc(this.photo, SlideController.photos[SlideController.photoId][0]);
-
- // Add caption from gallery array.
- Element.setInnerHTML(this.caption, SlideController.photos[SlideController.photoId][2]);
-
- try {
- document.title = document.title.replace(SlideController.photos[this.photoId][1],
- SlideController.photos[SlideController.photoId][1]);
- if (parent.frames.horde_main) {
- parent.document.title = document.title;
- }
- } catch (e) {}
- },
- updateLinks: function() {
-
- var params = '?gallery=' + SlideController.galleryId + '&image=' + SlideController.photos[SlideController.photoId][3] + '&page=' + SlideController.photos[SlideController.photoId][4];
-
- Element.setInnerHTML('PhotoName', SlideController.photos[SlideController.photoId][1]);
- Element.setInnerHTML('breadcrumb_image', SlideController.photos[SlideController.photoId][1]);
- Element.setHref($('breadcrumb_image'), SlideController.baseUrl + '/view.php' + params + '&view=Image');
- Element.setHref($('breadcrumb_gallery'), SlideController.baseUrl + '/view.php' + params + '&view=Gallery');
- if ($('image_properties_link')) {
- Element.setHref('image_properties_link', SlideController.baseUrl + '/image.php' + params + '&actionID=modify&share=' + SlideController.galleryShare);
- Element.setOnClick('image_properties_link', function(){SlideController.pause();Horde.popup({ url: this.href });return false;});
- }
- if ($('image_edit_link')) {
- Element.setHref('image_edit_link', SlideController.baseUrl + '/image.php' + params + '&actionID=editimage');
- }
- if ($('image_ecard_link')) {
- Element.setHref('image_ecard_link', SlideController.baseUrl + '/img/ecard.php?image=' + SlideController.photos[SlideController.photoId][3] + '&gallery=' + SlideController.galleryId);
- Element.setOnClick('image_ecard_link', function(){SlideController.pause();Horde.popup({ url: this.href });return false;});
- }
- if ($('image_delete_link')) {
- //TODO : Guess we should have PHP save the localized text for this...
- var deleteAction = function() {return window.confirm("Do you want to permanently delete " + SlideController.photos[SlideController.photoId][1])};
- Element.setHref($("image_delete_link"), SlideController.baseUrl + '/image.php' + params + '&actionID=delete');
- Element.setOnClick('image_delete_link', deleteAction);
- }
- Element.setHref('image_download_link', SlideController.baseUrl + '/img/download.php?image=' + SlideController.photos[SlideController.photoId][3]);
- Element.setOnClick('image_download_link', function(){SlideController.pause();});
- },
-
- showPhoto: function() {
- new Effect.Appear(this.photo, { duration: 1.0, queue: 'end', afterFinish: (function() { Element.show(this.captionBox); this.updateLinks();}).bind(this) });
-
- if (SlideController.playing) {
- if (SlideController.interval) {
- clearTimeout(SlideController.interval);
- }
- SlideController.interval = setTimeout(SlideController.next, SlideController.intervalSeconds * 1000);
- }
- },
- nextPhoto: function() {
- // Figure out which photo is next.
- (SlideController.photoId == (SlideController.photos.length - 1)) ? SlideController.photoId = 0 : ++SlideController.photoId;
- // Make sure the photo is loaded locally before we fade the current image.
- SlideController.tempImage.src = SlideController.photos[SlideController.photoId][0];
-
- },
- prevPhoto: function() {
- // Figure out which photo is previous.
- (SlideController.photoId == 0) ? SlideController.photoId = SlideController.photos.length - 1 : --SlideController.photoId;
- SlideController.tempImage.src = SlideController.photos[SlideController.photoId][0];
- },
- initSwap: function() {
- // Begin by hiding main elements.
- new Effect.Fade(this.captionBox, {duration: 0.5 });
- new Effect.Fade(this.photo, { duration: 1.0, afterFinish: (function() { SlideController.photo.setNewPhotoParams();})});
-
- // Update the current photo id.
- this.photoId = SlideController.photoId;
- }
-}
- // Arrow keys for navigation
- document.observe('keydown', arrowHandler);
-function arrowHandler(e)
-{
- if (e.altKey || e.shiftKey || e.ctrlKey) {
- return;
- }
-
- switch (e.keyCode || e.charCode) {
- case Event.KEY_LEFT:
- SlideController.prev();
- break;
-
- case Event.KEY_RIGHT:
- SlideController.next();
- break;
- }
-}
+++ /dev/null
-function checkSlug()
-{
- slug = document.gallery.gallery_slug.value;
- // Empty slugs are always allowed.
- if (!slug.length) {
- return true;
- }
-
- if (slug != Ansel.ajax.gallerySlugCheck.slugText) {
- var url = Ansel.ajax.gallerySlugCheck.url;
- var params = new Object();
- params.slug = slug;
- new Ajax.Request(url, {
- method: 'post',
- parameters: params,
- onComplete: function(transport) {
- var slugFlag = $('slug_flag');
- response = transport.responseJSON.response;
- if (response == 1) {
- if (slugFlag.hasClassName('problem')) {
- slugFlag.removeClassName('problem');
- }
- slugFlag.addClassName('success');
- $('gallery_submit').enable();
- // In case we try various slugs
- Ansel.ajax.gallerySlugCheck.slugText = slug;
- } else {
- if (slugFlag.hasClassName('success')) {
- slugFlag.removeClassName('success');
- }
- slugFlag.addClassName('problem');
- $('gallery_submit').disable();
- }
- }
- });
- } else {
- if (slugFlag.hasClassName('problem')) {
- slugFlag.removeClassName('problem');
- }
- slugFlag.addClassName('success');
- $('gallery_submit').enable();
- }
-}
+++ /dev/null
-function addTag()
-{
- if (!$('addtag').value.blank()) {
- var params = new Object();
- params.action = 'add';
- params[Ansel.ajax.tagActions.input] = $('addtag').value;
- new Ajax.Request(Ansel.ajax.tagActions.url,
- {
- method: 'post',
- parameters: params,
- onComplete: function(r) {
- $('addtag').value = "";
- if (r.responseJSON.response == 1) {
- $('tags').update(r.responseJSON.message);
- }
- }
- });
- }
-
- return true;
-}
-
-function removeTag(tagid)
-{
- var params = new Object();
- params.action = 'remove';
- params[Ansel.ajax.tagActions.input] = tagid;
- new Ajax.Request(Ansel.ajax.tagActions.url,
- {
- method: 'post',
- parameters: params,
- onComplete: function(r) {
- if (r.responseJSON.response == 1) {
- $('tags').update(r.responseJSON.message);
- }
- }
- });
-
- return true;
-}
-
-// Since onsubmit is never called when submitting programatically we
-// can use this function to add tags when we press enter on the tag form.
-function submitcheck()
-{
- return !addTag();
-}
\ No newline at end of file
+++ /dev/null
-/**
- * @param string node The DOM id of the node to show or hide.
- * The node that contains the toggle link should be named
- * {node}-toggle
- *
- * @param string requestType The class name of the Ajax_Imple type for this
- * widget.
- *
- */
-function doActionToggle(node, requestType)
-{
- $(node).toggle();
- togglePlusMinus(node, requestType);
- return false;
-}
-
-function togglePlusMinus(node, requestType)
-{
- var pref_value;
-
- if ($(node + '-toggle').hasClassName('show')) {
- $(node + '-toggle').removeClassName('show');
- $(node + '-toggle').addClassName('hide');
- var pref_value = 1;
- } else if ($(node + '-toggle').hasClassName('hide')) {
- $(node + '-toggle').removeClassName('hide');
- $(node + '-toggle').addClassName('show');
- var pref_value = 0;
- }
-
- var url = Ansel.widgets[requestType].url;
-
- var params = new Object();
- params.pref_value = pref_value;
- new Ajax.Request(url, {
- parameters: params
- });
-}
\ No newline at end of file
--- /dev/null
+function addTag()
+{
+ if (!$('addtag').value.blank()) {
+ var params = new Object();
+ params.action = 'add';
+ params[Ansel.ajax.tagActions.input] = $('addtag').value;
+ new Ajax.Request(Ansel.ajax.tagActions.url,
+ {
+ method: 'post',
+ parameters: params,
+ onComplete: function(r) {
+ $('addtag').value = "";
+ if (r.responseJSON.response == 1) {
+ $('tags').update(r.responseJSON.message);
+ }
+ }
+ });
+ }
+
+ return true;
+}
+
+function removeTag(tagid)
+{
+ var params = new Object();
+ params.action = 'remove';
+ params[Ansel.ajax.tagActions.input] = tagid;
+ new Ajax.Request(Ansel.ajax.tagActions.url,
+ {
+ method: 'post',
+ parameters: params,
+ onComplete: function(r) {
+ if (r.responseJSON.response == 1) {
+ $('tags').update(r.responseJSON.message);
+ }
+ }
+ });
+
+ return true;
+}
+
+// Since onsubmit is never called when submitting programatically we
+// can use this function to add tags when we press enter on the tag form.
+function submitcheck()
+{
+ return !addTag();
+}
\ No newline at end of file
--- /dev/null
+/**
+ * @param string node The DOM id of the node to show or hide.
+ * The node that contains the toggle link should be named
+ * {node}-toggle
+ *
+ * @param string requestType The class name of the Ajax_Imple type for this
+ * widget.
+ *
+ */
+function doActionToggle(node, requestType)
+{
+ $(node).toggle();
+ togglePlusMinus(node, requestType);
+ return false;
+}
+
+function togglePlusMinus(node, requestType)
+{
+ var pref_value;
+
+ if ($(node + '-toggle').hasClassName('show')) {
+ $(node + '-toggle').removeClassName('show');
+ $(node + '-toggle').addClassName('hide');
+ var pref_value = 1;
+ } else if ($(node + '-toggle').hasClassName('hide')) {
+ $(node + '-toggle').removeClassName('hide');
+ $(node + '-toggle').addClassName('show');
+ var pref_value = 0;
+ }
+
+ var url = Ansel.widgets[requestType].url;
+
+ var params = new Object();
+ params.pref_value = pref_value;
+ new Ajax.Request(url, {
+ parameters: params
+ });
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Chora annotate.php javascript code.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ */
+
+var Chora_Annotate = {
+ showLog: function(e) {
+ var elt = e.element(), rev, newelt;
+ if (!elt.hasClassName('logdisplay')) {
+ elt = elt.up('SPAN.logdisplay');
+ if (!elt) {
+ return;
+ }
+ }
+
+ e.stop();
+
+ rev = elt.hide().up('TD').down('A').readAttribute('rev');
+ newelt = new Element('TD', { colspan: 5 }).insert(Chora.loading_text);
+
+ elt.up('TR').insert({ after: new Element('TR', { className: 'logentry' }).insert(newelt) });
+
+ new Ajax.Updater(newelt, Chora.ANNOTATE_URL + rev);
+ }
+};
+
+document.observe('click', Chora_Annotate.showLog.bindAsEventListener(Chora_Annotate));
--- /dev/null
+/**
+ * Revision log javascript.
+ */
+
+var Chora_RevLog = {
+
+ selected: null,
+
+ highlight: function()
+ {
+ $('revlog_body').select('TR').each(function(tr) {
+ if (Prototype.Browser.IE) {
+ tr.observe('mouseover', this.rowover.bindAsEventListener(this, 'over'));
+ tr.observe('mouseover', this.rowover.bindAsEventListener(this, 'out'));
+ }
+ tr.observe('click', this.toggle.bindAsEventListener(this));
+ }, this);
+ },
+
+ rowover: function(e, type)
+ {
+ e.element().invoke(type == 'over' ? 'addClassName' : 'removeClassName', 'hover');
+ },
+
+ toggle: function(e)
+ {
+ // Ignore clicks on links.
+ var elt = e.element();
+ if (elt.tagName.toUpperCase() != 'TR') {
+ if (elt.tagName.toUpperCase() == 'A' &&
+ elt.readAttribute('href')) {
+ return;
+ }
+ elt = elt.up('TR');
+ }
+
+ if (this.selected != null) {
+ this.selected.removeClassName('selected');
+ if (this.selected == elt) {
+ this.selected = null;
+ $('revlog_body').removeClassName('selection');
+ return;
+ }
+ }
+
+ this.selected = elt;
+ elt.addClassName('selected');
+ $('revlog_body').addClassName('selection');
+ },
+
+ sdiff: function(link)
+ {
+ link = $(link);
+ link.writeAttribute('href', link.readAttribute('href').replace(/r1=([\d\.]+)/, 'r1=' + this.selected.identify().substring(3)));
+ }
+};
+
+document.observe('dom:loaded', Chora_RevLog.highlight.bind(Chora_RevLog));
+++ /dev/null
-/**
- * Chora annotate.php javascript code.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- */
-
-var Chora_Annotate = {
- showLog: function(e) {
- var elt = e.element(), rev, newelt;
- if (!elt.hasClassName('logdisplay')) {
- elt = elt.up('SPAN.logdisplay');
- if (!elt) {
- return;
- }
- }
-
- e.stop();
-
- rev = elt.hide().up('TD').down('A').readAttribute('rev');
- newelt = new Element('TD', { colspan: 5 }).insert(Chora.loading_text);
-
- elt.up('TR').insert({ after: new Element('TR', { className: 'logentry' }).insert(newelt) });
-
- new Ajax.Updater(newelt, Chora.ANNOTATE_URL + rev);
- }
-};
-
-document.observe('click', Chora_Annotate.showLog.bindAsEventListener(Chora_Annotate));
+++ /dev/null
-/**
- * Revision log javascript.
- */
-
-var Chora_RevLog = {
-
- selected: null,
-
- highlight: function()
- {
- $('revlog_body').select('TR').each(function(tr) {
- if (Prototype.Browser.IE) {
- tr.observe('mouseover', this.rowover.bindAsEventListener(this, 'over'));
- tr.observe('mouseover', this.rowover.bindAsEventListener(this, 'out'));
- }
- tr.observe('click', this.toggle.bindAsEventListener(this));
- }, this);
- },
-
- rowover: function(e, type)
- {
- e.element().invoke(type == 'over' ? 'addClassName' : 'removeClassName', 'hover');
- },
-
- toggle: function(e)
- {
- // Ignore clicks on links.
- var elt = e.element();
- if (elt.tagName.toUpperCase() != 'TR') {
- if (elt.tagName.toUpperCase() == 'A' &&
- elt.readAttribute('href')) {
- return;
- }
- elt = elt.up('TR');
- }
-
- if (this.selected != null) {
- this.selected.removeClassName('selected');
- if (this.selected == elt) {
- this.selected = null;
- $('revlog_body').removeClassName('selection');
- return;
- }
- }
-
- this.selected = elt;
- elt.addClassName('selected');
- $('revlog_body').addClassName('selection');
- },
-
- sdiff: function(link)
- {
- link = $(link);
- link.writeAttribute('href', link.readAttribute('href').replace(/r1=([\d\.]+)/, 'r1=' + this.selected.identify().substring(3)));
- }
-};
-
-document.observe('dom:loaded', Chora_RevLog.highlight.bind(Chora_RevLog));
--- /dev/null
+// Copyright 2006 Sébastien Gruhier (http://xilinus.com, http://itseb.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-trunk
+
+if(typeof Draggable == 'undefined')
+ throw("widget.js requires including script.aculo.us' dragdrop.js library");
+
+if(typeof Builder == 'undefined')
+ throw("widget.js requires including script.aculo.us' builder.js library");
+
+// Xilinus namespace
+if(typeof Xilinus == 'undefined')
+ Xilinus = {}
+
+Builder.dump();
+
+
+Xilinus.Widget = Class.create();
+Xilinus.Widget.lastId = 0;
+Xilinus.Widget.remove = function(element, options) {
+ if (options && options.afterFinish)
+ options.afterFinish.call();
+}
+
+Object.extend(Xilinus.Widget.prototype, {
+ initialize: function(className, id) {
+ className = className || "widget";
+ this._id = id || ("widget_" + Xilinus.Widget.lastId++);
+
+ this._titleDiv = DIV({className: 'header', id: this._getId("header")}, "");
+ this._contentDiv = DIV({className: 'headerbox', id: this._getId("content")}, "");
+ this._footerDiv = DIV({className: className + '_statusbar', id: this._getId("footer")}, "");
+
+ var divHeader = DIV({className: 'header' }, this._titleDiv);
+ var divContent = DIV({className: 'headerbox' }, this._contentDiv);
+ var divFooter = DIV({className: className + '_sw' }, this._footerDiv);
+
+ this._div = DIV({className: className + (className != "widget" ? " widget" : ""), id: this._getId()}, [divHeader, divContent, divFooter]);
+ this._div.widget = this;
+
+ return this;
+ },
+
+ destroy: function() {
+ this._div.remove();
+ },
+
+ getElement: function() {
+ return $(this._getId()) || $(this._div);
+ },
+
+ setTitle: function(title) {
+ $(this._titleDiv).update(title);
+ return this;
+ },
+
+ getTitle: function(title) {
+ return $(this._titleDiv)
+ },
+
+ setFooter: function(title) {
+ $(this._footerDiv).update(title);
+ return this;
+ },
+
+ getFooter: function(title) {
+ return $(this._footerDiv)
+ },
+
+ setContent: function(title) {
+ $(this._contentDiv).update(title);
+ return this;
+ },
+
+ getContent: function(title) {
+ return $(this._contentDiv)
+ },
+
+ updateHeight: function() {
+ $(this._contentDiv).setStyle({height: null})
+
+ var h = $(this._contentDiv).getHeight();
+ $(this._contentDiv).setStyle({height: h + "px"})
+ },
+
+ // PRIVATE FUNCTIONS
+ _getId: function(prefix) {
+ return (prefix ? prefix + "_" : "") + this._id;
+ }
+});
+
+
+Xilinus.Portal = Class.create()
+Object.extend(Xilinus.Portal.prototype, {
+ lastEvent: null,
+ widgets: null,
+ columns: null,
+
+ initialize: function(columns, options) {
+ this.options = Object.extend({
+ url: null, // Url called by Ajax.Request after a drop
+ onOverWidget: null, // Called when the mouse goes over a widget
+ onOutWidget: null, // Called when the mouse goes out of a widget
+ onChange: null, // Called a widget has been move during drag and drop
+ onUpdate: null, // Called a widget has been move after drag and drop
+ removeEffect: Xilinus.Widget.remove // Remove effect (by default no effect), you can set it to Effect.SwitchOff for example
+ }, options)
+ this._columns = (typeof columns == "string") ? $$(columns) : columns;
+ this._widgets = new Array();
+ this._columns.each(function(element) {Droppables.add(element, {onHover: this.onHover.bind(this),
+ overlap: "vertical",
+ accept: this.options.accept})}.bind(this));
+ this._outTimer = null;
+
+ // Draggable calls makePositioned for IE fix (??), I had to remove it for all browsers fix :) to handle properly zIndex
+ this._columns.invoke("undoPositioned");
+
+ this._currentOverWidget = null;
+ this._widgetMouseOver = this.widgetMouseOver.bindAsEventListener(this);
+ this._widgetMouseOut = this.widgetMouseOut.bindAsEventListener(this);
+
+ Draggables.addObserver({ onEnd: this.endDrag.bind(this), onStart: this.startDrag.bind(this) });
+ },
+
+ add: function(widget, columnIndex, draggable) {
+ draggable = typeof draggable == "undefined" ? true : draggable
+ // Add to widgets list
+ this._widgets.push(widget);
+ if (this.options.accept)
+ widget.getElement().addClassName(this.options.accept)
+ // Add element to column
+ this._columns[columnIndex].appendChild(widget.getElement());
+ widget.updateHeight();
+
+ // Make header draggable
+ if (draggable) {
+ widget.draggable = new Draggable(widget.getElement(),{ handle: widget._titleDiv, revert: false});
+ widget.getTitle().addClassName("widget_draggable");
+ }
+
+ // Update columns heights
+ this._updateColumnsHeight();
+
+ // Add mouse observers
+ if (this.options.onOverWidget)
+ widget.getElement().immediateDescendants().invoke("observe", "mouseover", this._widgetMouseOver);
+ if (this.options.onOutWidget)
+ widget.getElement().immediateDescendants().invoke("observe", "mouseout", this._widgetMouseOut);
+ },
+
+ remove: function(widget) {
+ // Remove from the list
+ this._widgets.reject(function(w) { return w == widget});
+
+ // Remove observers
+ if (this.options.onOverWidget)
+ widget.getElement().immediateDescendants().invoke("stopObserving", "mouseover", this._widgetMouseOver);
+ if (this.options.onOutWidget)
+ widget.getElement().immediateDescendants().invoke("stopObserving", "mouseout", this._widgetMouseOut);
+
+ // Remove draggable
+ if (widget.draggable)
+ widget.draggable.destroy();
+
+ // Remove from the dom
+ this.options.removeEffect(widget.getElement(), {afterFinish: function() {widget.destroy();}});
+
+ // Update columns heights
+ this._updateColumnsHeight();
+ },
+
+ serialize: function() {
+ parameters = ""
+ this._columns.each(function(column) {
+ var p = column.immediateDescendants().collect(function(element) {
+ return column.id + "[]=" + element.id
+ }).join("&")
+ parameters += p + "&"
+ });
+
+ return parameters;
+ },
+
+ addWidgetControls: function(element) {
+ $(element).observe("mouseover", this._widgetMouseOver);
+ $(element).observe("mouseout", this._widgetMouseOut);
+ },
+
+ // EVENTS CALLBACKS
+ widgetMouseOver: function(event) {
+ this._clearTimer();
+
+ var element = Event.element(event).up(".widget");
+ if (this._currentOverWidget == null || this._currentOverWidget != element) {
+ if (this._currentOverWidget && this._currentOverWidget != element)
+ this.options.onOutWidget(this, this._currentOverWidget.widget)
+
+ this._currentOverWidget = element;
+ this.options.onOverWidget(this, element.widget)
+ }
+ },
+
+ widgetMouseOut: function(event) {
+ this._clearTimer();
+ var element = Event.element(event).up(".widget");
+ this._outTimer = setTimeout(this._doWidgetMouseOut.bind(this, element), 100);
+ },
+
+ _doWidgetMouseOut: function(element) {
+ this._currentOverWidget = null;
+ this.options.onOutWidget(this, element.widget)
+ },
+
+ // DRAGGABLE OBSERVER CALLBACKS
+ startDrag: function(eventName, draggable) {
+ var widget = draggable.element;
+
+ if (!this._widgets.find(function(w) {return w == widget.widget}))
+ return;
+
+ var column = widget.parentNode;
+
+ // Create and insert ghost widget
+ var ghost = DIV({className: 'widget_ghost'}, "");
+ $(ghost).setStyle({height: widget.getHeight() + 'px'})
+
+ column.insertBefore(ghost, widget);
+
+ // IE Does not absolutize properly the widget, needs to set width before
+ widget.setStyle({width: widget.getWidth() + "px"});
+
+ // Absolutize and move widget on body
+ Position.absolutize(widget);
+ document.body.appendChild(widget);
+
+ // Store ghost to drag widget for later use
+ draggable.element.ghost = ghost;
+
+ // Store current position
+ this._savePosition = this.serialize();
+ },
+
+ endDrag: function(eventName, draggable) {
+ var widget = draggable.element;
+ if (!this._widgets.find(function(w) {return w == widget.widget}))
+ return;
+
+ var column = widget.ghost.parentNode;
+
+ column.insertBefore(draggable.element, widget.ghost);
+ widget.ghost.remove();
+
+ if (Prototype.Browser.Opera)
+ widget.setStyle({top: 0, left: 0, width: "100%", height: widget._originalHeight, zIndex: null, opacity: null, position: "relative"})
+ else
+ widget.setStyle({top: null, left: null, width: null, height: widget._originalHeight, zIndex: null, opacity: null, position: "relative"})
+
+ widget.ghost = null;
+ widget.widget.updateHeight();
+ this._updateColumnsHeight();
+
+ // Fire events if changed
+ if (this._savePosition != this.serialize()) {
+ if (this.options.url)
+ new Ajax.Request(this.options.url, {parameters: this.serialize()});
+
+ if (this.options.onUpdate)
+ this.options.onUpdate(this);
+ }
+ },
+
+ onHover: function(dragWidget, dropon, overlap) {
+ var offset = Position.cumulativeOffset(dropon);
+ var x = offset[0] + 10;
+ var y = offset[1] + (1 - overlap) * dropon.getHeight();
+
+ // Check over ghost widget
+ if (Position.within(dragWidget.ghost, x, y))
+ return;
+
+ // Find if it's overlapping a widget
+ var found = false;
+ var moved = false;
+ for (var index = 0, len = this._widgets.length; index < len; ++index) {
+ var w = this._widgets[index].getElement();
+ if (w == dragWidget || w.parentNode != dropon)
+ continue;
+
+ if (Position.within(w, x, y)) {
+ var overlap = Position.overlap( 'vertical', w);
+ // Bottom of the widget
+ if (overlap < 0.5) {
+ // Check if the ghost widget is not already below this widget
+ if (w.next() != dragWidget.ghost) {
+ w.parentNode.insertBefore(dragWidget.ghost, w.next());
+ moved = true;
+ }
+ }
+ // Top of the widget
+ else {
+ // Check if the ghost widget is not already above this widget
+ if (w.previous() != dragWidget.ghost) {
+ w.parentNode.insertBefore(dragWidget.ghost, w);
+ moved = true;
+ }
+ }
+ found = true;
+ break;
+ }
+ }
+ // Not found a widget
+ if (! found) {
+ // Check if dropon has ghost widget
+ if (dragWidget.ghost.parentNode != dropon) {
+ // Get last widget bottom value
+ var last = dropon.immediateDescendants().last();
+ var yLast = last ? Position.cumulativeOffset(last)[1] + last.getHeight() : 0;
+ if (y > yLast && last != dragWidget.ghost) {
+ dropon.appendChild(dragWidget.ghost);
+ moved = true;
+ }
+ }
+ }
+ if (moved && this.options.onChange)
+ this.options.onChange(this)
+
+ this._updateColumnsHeight();
+ },
+
+ // PRIVATE FUNCTIONS
+ _updateColumnsHeight: function() {
+ var h = 0;
+ this._columns.each(function(col) {
+ h = Math.max(h, col.immediateDescendants().inject(0, function(sum, element) {
+ return sum + element.getHeight();
+ }));
+ })
+ this._columns.invoke("setStyle", {height: h + 'px'})
+ },
+
+ _clearTimer: function() {
+ if (this._outTimer) {
+ clearTimeout(this._outTimer);
+ this._outTimer = null;
+ }
+ }
+});
--- /dev/null
+
+var _widgets_blocks = new Array();
+var _layout_params = new Array();
+
+function onOverWidget(portal, widget) {
+ widget.getElement().insertBefore($('control_buttons'), widget.getElement().firstChild);
+ $('control_buttons').show();
+}
+
+function onOutWidget(portal, widget) {
+ $('control_buttons').hide();
+}
+
+function minimizeWidget(element) {
+ var widget = $(element).up(".widget").widget;
+ id = widget._getId().substr(7);
+ if ($('content_widget_' + id).style.display == 'none') {
+ $('content_widget_' + id).style.display = 'block';
+ element.id = 'minimize_button';
+ } else {
+ $('content_widget_' + id).style.display = 'none';
+ element.id = 'maximize_button';
+ }
+}
+
+function removeWidget(element) {
+ var widget = $(element).up(".widget").widget;
+
+ if (confirm(confirm_remove)) {
+ document.body.appendChild($('control_buttons').hide())
+ portal.remove(widget);
+ }
+}
+
+function listWidgets() {
+
+ RedBox.loading();
+
+ // load edit options
+ new Ajax.Request(list_url, {
+ method: 'get',
+ onSuccess: function(transport) {
+ RedBox.showHtml('<div id="RB_info">' + transport.responseText + '</div>');
+ },
+ onFailure: function(transport) {
+ RedBox.close();
+ }
+ });
+}
+
+function addWidget() {
+
+ // Add widget
+ select = $('block_selection');
+ title = select.options[select.selectedIndex].text;
+
+ widget = new Xilinus.Widget();
+ widget.setTitle(title);
+ widget.setContent(title);
+ portal.add(widget, parseInt($F('block_column')));
+
+ _widgets_blocks[_widgets_blocks.length] = select.value;
+ _layout_params[_widgets_blocks.length] = new Array();
+
+ // Edit wiget
+ editWidget(widget);
+
+ cancelRedBox();
+}
+
+function reloadWidget(element) {
+
+ if ($(element).id == 'reload_button') {
+ var widget = $(element).up(".widget").widget;
+ } else {
+ var widget = element;
+ }
+
+ var id = widget._getId().substr(7);
+
+ new Ajax.Request(load_url, {
+ parameters: getAjaxParameters(element),
+ method: 'get',
+ onSuccess: function(transport) {
+ block_data = transport.responseText.evalJSON(true);
+ widget.setTitle(block_data['title']);
+ widget.setContent(block_data['content']);
+ _widgets_blocks[widget._getId().substr(7)] = block_used;
+ },
+ onFailure: function(transport) {
+ alert('Someting gone wrong.');
+ }
+ });
+}
+
+function editWidget(element) {
+
+ if ($(element).id == 'reload_button') {
+ var widget = $(element).up(".widget").widget;
+ } else {
+ var widget = element;
+ }
+
+ new Ajax.Request(edit_url, {
+ parameters: getAjaxParameters(element),
+ method: 'get',
+ onSuccess: function(transport) {
+ RedBox.showHtml('<div id="RB_info">' + transport.responseText + '</div>');
+ },
+ onFailure: function(transport) {
+ RedBox.close();
+ }
+ });
+
+}
+
+function getAjaxParameters(element) {
+
+ if ($(element).id == 'reload_button' || $(element).id == 'edit_button') {
+ var widget = $(element).up(".widget").widget;
+ } else {
+ var widget = element;
+ }
+
+ var id = widget._getId().substr(7);
+
+ parameters = 'block=' + _widgets_blocks[id];
+ parameters = parameters + '&widget=' + widget._getId();
+
+ p = _layout_params[id];
+ for (a in p) {
+ if (typeof(p[a]) != 'string') {
+ break;
+ }
+ parameters = parameters + '&defaults[' + a + ']=' + p[a];
+ }
+
+ return parameters;
+}
+
+function setParams() {
+
+ widget_name = '';
+ params = new Array();
+ inputs = $('blockform').getElements();
+ inputs.each(function(item) {
+ name = item.name.substr(0, 6);
+ if (name == 'params') {
+ pos = item.name.indexOf(']', 7);
+ param_name = item.name.substr(7, pos - 7);
+ if (item.type == 'checkbox') {
+ params[param_name] = item.checked;
+ } else {
+ params[param_name] = item.value;
+ }
+ }
+ if (name == 'widget') {
+ widget_name = item.value;
+ }
+ });
+
+ _layout_params[widget_name.substr(7)] = params;
+
+ var widget = $(widget_name).widget;
+ reloadWidget(widget);
+
+ cancelRedBox();
+}
+
+function noParams(widget_name, msg) {
+
+ // alert(msg);
+
+ var widget = $(widget_name).widget;
+ reloadWidget(widget);
+
+ cancelRedBox();
+}
+
+function cancelRedBox() {
+ RedBox.close();
+ return false;
+}
+
+function savePortal() {
+
+ parameters = portal.serialize();
+
+ for (var i = 0; i < _layout_params.length; i++) {
+ parameters = parameters + '¶ms[' + i + '][type]=' + _widgets_blocks[i];
+ p = _layout_params[i];
+ for (a in p) {
+ if (typeof(p[a]) != 'string') {
+ break;
+ }
+ parameters = parameters + '¶ms[' + i + '][' + a + ']=' + p[a];
+ }
+ }
+
+ new Ajax.Request(save_url, {
+ parameters: parameters,
+ method: 'post'
+ });
+}
+++ /dev/null
-// Copyright 2006 Sébastien Gruhier (http://xilinus.com, http://itseb.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-trunk
-
-if(typeof Draggable == 'undefined')
- throw("widget.js requires including script.aculo.us' dragdrop.js library");
-
-if(typeof Builder == 'undefined')
- throw("widget.js requires including script.aculo.us' builder.js library");
-
-// Xilinus namespace
-if(typeof Xilinus == 'undefined')
- Xilinus = {}
-
-Builder.dump();
-
-
-Xilinus.Widget = Class.create();
-Xilinus.Widget.lastId = 0;
-Xilinus.Widget.remove = function(element, options) {
- if (options && options.afterFinish)
- options.afterFinish.call();
-}
-
-Object.extend(Xilinus.Widget.prototype, {
- initialize: function(className, id) {
- className = className || "widget";
- this._id = id || ("widget_" + Xilinus.Widget.lastId++);
-
- this._titleDiv = DIV({className: 'header', id: this._getId("header")}, "");
- this._contentDiv = DIV({className: 'headerbox', id: this._getId("content")}, "");
- this._footerDiv = DIV({className: className + '_statusbar', id: this._getId("footer")}, "");
-
- var divHeader = DIV({className: 'header' }, this._titleDiv);
- var divContent = DIV({className: 'headerbox' }, this._contentDiv);
- var divFooter = DIV({className: className + '_sw' }, this._footerDiv);
-
- this._div = DIV({className: className + (className != "widget" ? " widget" : ""), id: this._getId()}, [divHeader, divContent, divFooter]);
- this._div.widget = this;
-
- return this;
- },
-
- destroy: function() {
- this._div.remove();
- },
-
- getElement: function() {
- return $(this._getId()) || $(this._div);
- },
-
- setTitle: function(title) {
- $(this._titleDiv).update(title);
- return this;
- },
-
- getTitle: function(title) {
- return $(this._titleDiv)
- },
-
- setFooter: function(title) {
- $(this._footerDiv).update(title);
- return this;
- },
-
- getFooter: function(title) {
- return $(this._footerDiv)
- },
-
- setContent: function(title) {
- $(this._contentDiv).update(title);
- return this;
- },
-
- getContent: function(title) {
- return $(this._contentDiv)
- },
-
- updateHeight: function() {
- $(this._contentDiv).setStyle({height: null})
-
- var h = $(this._contentDiv).getHeight();
- $(this._contentDiv).setStyle({height: h + "px"})
- },
-
- // PRIVATE FUNCTIONS
- _getId: function(prefix) {
- return (prefix ? prefix + "_" : "") + this._id;
- }
-});
-
-
-Xilinus.Portal = Class.create()
-Object.extend(Xilinus.Portal.prototype, {
- lastEvent: null,
- widgets: null,
- columns: null,
-
- initialize: function(columns, options) {
- this.options = Object.extend({
- url: null, // Url called by Ajax.Request after a drop
- onOverWidget: null, // Called when the mouse goes over a widget
- onOutWidget: null, // Called when the mouse goes out of a widget
- onChange: null, // Called a widget has been move during drag and drop
- onUpdate: null, // Called a widget has been move after drag and drop
- removeEffect: Xilinus.Widget.remove // Remove effect (by default no effect), you can set it to Effect.SwitchOff for example
- }, options)
- this._columns = (typeof columns == "string") ? $$(columns) : columns;
- this._widgets = new Array();
- this._columns.each(function(element) {Droppables.add(element, {onHover: this.onHover.bind(this),
- overlap: "vertical",
- accept: this.options.accept})}.bind(this));
- this._outTimer = null;
-
- // Draggable calls makePositioned for IE fix (??), I had to remove it for all browsers fix :) to handle properly zIndex
- this._columns.invoke("undoPositioned");
-
- this._currentOverWidget = null;
- this._widgetMouseOver = this.widgetMouseOver.bindAsEventListener(this);
- this._widgetMouseOut = this.widgetMouseOut.bindAsEventListener(this);
-
- Draggables.addObserver({ onEnd: this.endDrag.bind(this), onStart: this.startDrag.bind(this) });
- },
-
- add: function(widget, columnIndex, draggable) {
- draggable = typeof draggable == "undefined" ? true : draggable
- // Add to widgets list
- this._widgets.push(widget);
- if (this.options.accept)
- widget.getElement().addClassName(this.options.accept)
- // Add element to column
- this._columns[columnIndex].appendChild(widget.getElement());
- widget.updateHeight();
-
- // Make header draggable
- if (draggable) {
- widget.draggable = new Draggable(widget.getElement(),{ handle: widget._titleDiv, revert: false});
- widget.getTitle().addClassName("widget_draggable");
- }
-
- // Update columns heights
- this._updateColumnsHeight();
-
- // Add mouse observers
- if (this.options.onOverWidget)
- widget.getElement().immediateDescendants().invoke("observe", "mouseover", this._widgetMouseOver);
- if (this.options.onOutWidget)
- widget.getElement().immediateDescendants().invoke("observe", "mouseout", this._widgetMouseOut);
- },
-
- remove: function(widget) {
- // Remove from the list
- this._widgets.reject(function(w) { return w == widget});
-
- // Remove observers
- if (this.options.onOverWidget)
- widget.getElement().immediateDescendants().invoke("stopObserving", "mouseover", this._widgetMouseOver);
- if (this.options.onOutWidget)
- widget.getElement().immediateDescendants().invoke("stopObserving", "mouseout", this._widgetMouseOut);
-
- // Remove draggable
- if (widget.draggable)
- widget.draggable.destroy();
-
- // Remove from the dom
- this.options.removeEffect(widget.getElement(), {afterFinish: function() {widget.destroy();}});
-
- // Update columns heights
- this._updateColumnsHeight();
- },
-
- serialize: function() {
- parameters = ""
- this._columns.each(function(column) {
- var p = column.immediateDescendants().collect(function(element) {
- return column.id + "[]=" + element.id
- }).join("&")
- parameters += p + "&"
- });
-
- return parameters;
- },
-
- addWidgetControls: function(element) {
- $(element).observe("mouseover", this._widgetMouseOver);
- $(element).observe("mouseout", this._widgetMouseOut);
- },
-
- // EVENTS CALLBACKS
- widgetMouseOver: function(event) {
- this._clearTimer();
-
- var element = Event.element(event).up(".widget");
- if (this._currentOverWidget == null || this._currentOverWidget != element) {
- if (this._currentOverWidget && this._currentOverWidget != element)
- this.options.onOutWidget(this, this._currentOverWidget.widget)
-
- this._currentOverWidget = element;
- this.options.onOverWidget(this, element.widget)
- }
- },
-
- widgetMouseOut: function(event) {
- this._clearTimer();
- var element = Event.element(event).up(".widget");
- this._outTimer = setTimeout(this._doWidgetMouseOut.bind(this, element), 100);
- },
-
- _doWidgetMouseOut: function(element) {
- this._currentOverWidget = null;
- this.options.onOutWidget(this, element.widget)
- },
-
- // DRAGGABLE OBSERVER CALLBACKS
- startDrag: function(eventName, draggable) {
- var widget = draggable.element;
-
- if (!this._widgets.find(function(w) {return w == widget.widget}))
- return;
-
- var column = widget.parentNode;
-
- // Create and insert ghost widget
- var ghost = DIV({className: 'widget_ghost'}, "");
- $(ghost).setStyle({height: widget.getHeight() + 'px'})
-
- column.insertBefore(ghost, widget);
-
- // IE Does not absolutize properly the widget, needs to set width before
- widget.setStyle({width: widget.getWidth() + "px"});
-
- // Absolutize and move widget on body
- Position.absolutize(widget);
- document.body.appendChild(widget);
-
- // Store ghost to drag widget for later use
- draggable.element.ghost = ghost;
-
- // Store current position
- this._savePosition = this.serialize();
- },
-
- endDrag: function(eventName, draggable) {
- var widget = draggable.element;
- if (!this._widgets.find(function(w) {return w == widget.widget}))
- return;
-
- var column = widget.ghost.parentNode;
-
- column.insertBefore(draggable.element, widget.ghost);
- widget.ghost.remove();
-
- if (Prototype.Browser.Opera)
- widget.setStyle({top: 0, left: 0, width: "100%", height: widget._originalHeight, zIndex: null, opacity: null, position: "relative"})
- else
- widget.setStyle({top: null, left: null, width: null, height: widget._originalHeight, zIndex: null, opacity: null, position: "relative"})
-
- widget.ghost = null;
- widget.widget.updateHeight();
- this._updateColumnsHeight();
-
- // Fire events if changed
- if (this._savePosition != this.serialize()) {
- if (this.options.url)
- new Ajax.Request(this.options.url, {parameters: this.serialize()});
-
- if (this.options.onUpdate)
- this.options.onUpdate(this);
- }
- },
-
- onHover: function(dragWidget, dropon, overlap) {
- var offset = Position.cumulativeOffset(dropon);
- var x = offset[0] + 10;
- var y = offset[1] + (1 - overlap) * dropon.getHeight();
-
- // Check over ghost widget
- if (Position.within(dragWidget.ghost, x, y))
- return;
-
- // Find if it's overlapping a widget
- var found = false;
- var moved = false;
- for (var index = 0, len = this._widgets.length; index < len; ++index) {
- var w = this._widgets[index].getElement();
- if (w == dragWidget || w.parentNode != dropon)
- continue;
-
- if (Position.within(w, x, y)) {
- var overlap = Position.overlap( 'vertical', w);
- // Bottom of the widget
- if (overlap < 0.5) {
- // Check if the ghost widget is not already below this widget
- if (w.next() != dragWidget.ghost) {
- w.parentNode.insertBefore(dragWidget.ghost, w.next());
- moved = true;
- }
- }
- // Top of the widget
- else {
- // Check if the ghost widget is not already above this widget
- if (w.previous() != dragWidget.ghost) {
- w.parentNode.insertBefore(dragWidget.ghost, w);
- moved = true;
- }
- }
- found = true;
- break;
- }
- }
- // Not found a widget
- if (! found) {
- // Check if dropon has ghost widget
- if (dragWidget.ghost.parentNode != dropon) {
- // Get last widget bottom value
- var last = dropon.immediateDescendants().last();
- var yLast = last ? Position.cumulativeOffset(last)[1] + last.getHeight() : 0;
- if (y > yLast && last != dragWidget.ghost) {
- dropon.appendChild(dragWidget.ghost);
- moved = true;
- }
- }
- }
- if (moved && this.options.onChange)
- this.options.onChange(this)
-
- this._updateColumnsHeight();
- },
-
- // PRIVATE FUNCTIONS
- _updateColumnsHeight: function() {
- var h = 0;
- this._columns.each(function(col) {
- h = Math.max(h, col.immediateDescendants().inject(0, function(sum, element) {
- return sum + element.getHeight();
- }));
- })
- this._columns.invoke("setStyle", {height: h + 'px'})
- },
-
- _clearTimer: function() {
- if (this._outTimer) {
- clearTimeout(this._outTimer);
- this._outTimer = null;
- }
- }
-});
+++ /dev/null
-
-var _widgets_blocks = new Array();
-var _layout_params = new Array();
-
-function onOverWidget(portal, widget) {
- widget.getElement().insertBefore($('control_buttons'), widget.getElement().firstChild);
- $('control_buttons').show();
-}
-
-function onOutWidget(portal, widget) {
- $('control_buttons').hide();
-}
-
-function minimizeWidget(element) {
- var widget = $(element).up(".widget").widget;
- id = widget._getId().substr(7);
- if ($('content_widget_' + id).style.display == 'none') {
- $('content_widget_' + id).style.display = 'block';
- element.id = 'minimize_button';
- } else {
- $('content_widget_' + id).style.display = 'none';
- element.id = 'maximize_button';
- }
-}
-
-function removeWidget(element) {
- var widget = $(element).up(".widget").widget;
-
- if (confirm(confirm_remove)) {
- document.body.appendChild($('control_buttons').hide())
- portal.remove(widget);
- }
-}
-
-function listWidgets() {
-
- RedBox.loading();
-
- // load edit options
- new Ajax.Request(list_url, {
- method: 'get',
- onSuccess: function(transport) {
- RedBox.showHtml('<div id="RB_info">' + transport.responseText + '</div>');
- },
- onFailure: function(transport) {
- RedBox.close();
- }
- });
-}
-
-function addWidget() {
-
- // Add widget
- select = $('block_selection');
- title = select.options[select.selectedIndex].text;
-
- widget = new Xilinus.Widget();
- widget.setTitle(title);
- widget.setContent(title);
- portal.add(widget, parseInt($F('block_column')));
-
- _widgets_blocks[_widgets_blocks.length] = select.value;
- _layout_params[_widgets_blocks.length] = new Array();
-
- // Edit wiget
- editWidget(widget);
-
- cancelRedBox();
-}
-
-function reloadWidget(element) {
-
- if ($(element).id == 'reload_button') {
- var widget = $(element).up(".widget").widget;
- } else {
- var widget = element;
- }
-
- var id = widget._getId().substr(7);
-
- new Ajax.Request(load_url, {
- parameters: getAjaxParameters(element),
- method: 'get',
- onSuccess: function(transport) {
- block_data = transport.responseText.evalJSON(true);
- widget.setTitle(block_data['title']);
- widget.setContent(block_data['content']);
- _widgets_blocks[widget._getId().substr(7)] = block_used;
- },
- onFailure: function(transport) {
- alert('Someting gone wrong.');
- }
- });
-}
-
-function editWidget(element) {
-
- if ($(element).id == 'reload_button') {
- var widget = $(element).up(".widget").widget;
- } else {
- var widget = element;
- }
-
- new Ajax.Request(edit_url, {
- parameters: getAjaxParameters(element),
- method: 'get',
- onSuccess: function(transport) {
- RedBox.showHtml('<div id="RB_info">' + transport.responseText + '</div>');
- },
- onFailure: function(transport) {
- RedBox.close();
- }
- });
-
-}
-
-function getAjaxParameters(element) {
-
- if ($(element).id == 'reload_button' || $(element).id == 'edit_button') {
- var widget = $(element).up(".widget").widget;
- } else {
- var widget = element;
- }
-
- var id = widget._getId().substr(7);
-
- parameters = 'block=' + _widgets_blocks[id];
- parameters = parameters + '&widget=' + widget._getId();
-
- p = _layout_params[id];
- for (a in p) {
- if (typeof(p[a]) != 'string') {
- break;
- }
- parameters = parameters + '&defaults[' + a + ']=' + p[a];
- }
-
- return parameters;
-}
-
-function setParams() {
-
- widget_name = '';
- params = new Array();
- inputs = $('blockform').getElements();
- inputs.each(function(item) {
- name = item.name.substr(0, 6);
- if (name == 'params') {
- pos = item.name.indexOf(']', 7);
- param_name = item.name.substr(7, pos - 7);
- if (item.type == 'checkbox') {
- params[param_name] = item.checked;
- } else {
- params[param_name] = item.value;
- }
- }
- if (name == 'widget') {
- widget_name = item.value;
- }
- });
-
- _layout_params[widget_name.substr(7)] = params;
-
- var widget = $(widget_name).widget;
- reloadWidget(widget);
-
- cancelRedBox();
-}
-
-function noParams(widget_name, msg) {
-
- // alert(msg);
-
- var widget = $(widget_name).widget;
- reloadWidget(widget);
-
- cancelRedBox();
-}
-
-function cancelRedBox() {
- RedBox.close();
- return false;
-}
-
-function savePortal() {
-
- parameters = portal.serialize();
-
- for (var i = 0; i < _layout_params.length; i++) {
- parameters = parameters + '¶ms[' + i + '][type]=' + _widgets_blocks[i];
- p = _layout_params[i];
- for (a in p) {
- if (typeof(p[a]) != 'string') {
- break;
- }
- parameters = parameters + '¶ms[' + i + '][' + a + ']=' + p[a];
- }
- }
-
- new Ajax.Request(save_url, {
- parameters: parameters,
- method: 'post'
- });
-}
--- /dev/null
+function saveSearch(url) {
+ RedBox.loading();
+ new Ajax.Request(url, {
+ parameters: {
+ ajax: 1
+ },
+ method: 'get',
+ onSuccess: function(transport) {
+ RedBox.showHtml('<div id="RB_info">' + transport.responseText + '</div>');
+ },
+ onFailure: function(transport) {
+ RedBox.close();
+ }
+ });
+}
+
+ function updateStatus(statusText, inputNode) {
+ {$spinner}.toggle();
+ params = new Object();
+ params.actionID = 'updateStatus';
+ params.statusText = statusText;
+ new Ajax.Updater({success:'currentStatus'},
+ '$endpoint',
+ {
+ method: 'post',
+ parameters: params,
+ onComplete: function() {inputNode.value = '';{$spinner}.toggle()},
+ onFailure: function() {{$spinner}.toggle()}
+ }
+ );
+ }
\ No newline at end of file
+++ /dev/null
-function saveSearch(url) {\r
- RedBox.loading();\r
- new Ajax.Request(url, {\r
- parameters: {\r
- ajax: 1\r
- },\r
- method: 'get',\r
- onSuccess: function(transport) {\r
- RedBox.showHtml('<div id="RB_info">' + transport.responseText + '</div>');\r
- },\r
- onFailure: function(transport) {\r
- RedBox.close();\r
- }\r
- });\r
-}\r
-\r
- function updateStatus(statusText, inputNode) {\r
- {$spinner}.toggle();\r
- params = new Object();\r
- params.actionID = 'updateStatus';\r
- params.statusText = statusText;\r
- new Ajax.Updater({success:'currentStatus'},\r
- '$endpoint',\r
- {\r
- method: 'post',\r
- parameters: params,\r
- onComplete: function() {inputNode.value = '';{$spinner}.toggle()},\r
- onFailure: function() {{$spinner}.toggle()}\r
- }\r
- );\r
- }
\ No newline at end of file
--- /dev/null
+/**
+ * Provides the javascript for the gollem column select preferences page.
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ */
+
+var columns = [];
+
+function selectSource()
+{
+ var f = document.prefs;
+ var fieldString = '';
+
+ while (f.unselected_columns.length > 1) {
+ f.unselected_columns.options[f.unselected_columns.length - 1] = null;
+ }
+ while (f.selected_columns.length > 1) {
+ f.selected_columns.options[f.selected_columns.length - 1] = null;
+ }
+
+ if (f.source.selectedIndex < 1) {
+ return;
+ }
+ var source = f.source.selectedIndex - 1;
+
+ var selected = [];
+ var unselected = [];
+ for (var i = 1; i < columns[source].length; i++) {
+ if (columns[source][i][2]) {
+ selected[columns[source][i][3]] = [columns[source][i][1], columns[source][i][0]];
+ } else {
+ unselected[unselected.length] = [columns[source][i][1], columns[source][i][0]];
+ }
+ }
+ for (i = 0; i < selected.length; i++) {
+ f.selected_columns.options[i + 1] = new Option(selected[i][0], selected[i][1]);
+ }
+ for (i = 0; i < unselected.length; i++) {
+ f.unselected_columns.options[i + 1] = new Option(unselected[i][0], unselected[i][1]);
+ }
+}
+
+function deselectHeaders()
+{
+ document.prefs.unselected_columns[0].selected = false;
+ document.prefs.selected_columns[0].selected = false;
+}
+
+function resetHidden()
+{
+ var tmp = '';
+ for (var i = 0; i < columns.length; i++) {
+ if (i > 0) {
+ tmp += '\n';
+ }
+ tmp += columns[i][0];
+ for (var j = 1; j < columns[i].length; j++) {
+ if (columns[i][j][2]) {
+ tmp += '\t' + columns[i][j][0];
+ }
+ }
+ }
+ document.prefs.columns.value = tmp;
+}
+
+function addColumn()
+{
+ var f = document.prefs;
+ var source = f.source.selectedIndex - 1;
+
+ for (i = 1; i < f.unselected_columns.length; i++) {
+ if (f.unselected_columns[i].selected) {
+ for (var j = 1; j < columns[source].length; j++) {
+ if (columns[source][j][0] == f.unselected_columns[i].value) {
+ columns[source][j][2] = true;
+ }
+ }
+ f.selected_columns[f.selected_columns.length] = new Option(f.unselected_columns[i].text, f.unselected_columns[i].value);
+ f.unselected_columns[i] = null;
+ i--;
+ }
+ }
+
+ resetHidden();
+}
+
+function removeColumn()
+{
+ var f = document.prefs;
+ var source = f.source.selectedIndex - 1;
+
+ for (i = 1; i < f.selected_columns.length; i++) {
+ if (f.selected_columns[i].selected) {
+ for (var j = 1; j < columns[source].length; j++) {
+ if (columns[source][j][0] == f.selected_columns[i].value) {
+ columns[source][j][2] = false;
+ }
+ }
+ f.unselected_columns[f.unselected_columns.length] = new Option(f.selected_columns[i].text, f.selected_columns[i].value)
+ f.selected_columns[i] = null;
+ i--;
+ }
+ }
+
+ resetHidden();
+}
+
+function moveColumnUp()
+{
+ var f = document.prefs;
+ var sel = f.selected_columns.selectedIndex;
+ var source = f.source.selectedIndex - 1;
+
+ if (sel <= 1 || f.selected_columns.length <= 2) return;
+
+ // deselect everything but the first selected item
+ f.selected_columns.selectedIndex = sel;
+ var up = f.selected_columns[sel].value;
+
+ tmp = [];
+ for (i = 1; i < f.selected_columns.length; i++) {
+ tmp[i - 1] = new Option(f.selected_columns[i].text, f.selected_columns[i].value)
+ }
+
+ for (i = 0; i < tmp.length; i++) {
+ if (i + 1 == sel - 1) {
+ f.selected_columns[i + 1] = tmp[i + 1];
+ } else if (i + 1 == sel) {
+ f.selected_columns[i + 1] = tmp[i - 1];
+ } else {
+ f.selected_columns[i + 1] = tmp[i];
+ }
+ }
+
+ f.selected_columns.selectedIndex = sel - 1;
+
+ for (i = 2; i < columns[source].length - 1; i++) {
+ if (columns[source][i][0] == up) {
+ column = columns[source][i];
+ columns[source][i] = columns[source][i - 1];
+ columns[source][i - 1] = column;
+ }
+ }
+
+ resetHidden();
+}
+
+function moveColumnDown()
+{
+ var f = document.prefs;
+ var sel = f.selected_columns.selectedIndex;
+ var source = f.source.selectedIndex - 1;
+
+ if (sel == -1 || f.selected_columns.length <= 2 || sel == f.selected_columns.length - 1) return;
+
+ // deselect everything but the first selected item
+ f.selected_columns.selectedIndex = sel;
+ var down = f.selected_columns[sel].value;
+
+ tmp = [];
+ for (i = 1; i < f.selected_columns.length; i++) {
+ tmp[i - 1] = new Option(f.selected_columns[i].text, f.selected_columns[i].value)
+ }
+
+ for (i = 0; i < tmp.length; i++) {
+ if (i + 1 == sel) {
+ f.selected_columns[i + 1] = tmp[i + 1];
+ } else if (i + 1 == sel + 1) {
+ f.selected_columns[i + 1] = tmp[i - 1];
+ } else {
+ f.selected_columns[i + 1] = tmp[i];
+ }
+ }
+
+ f.selected_columns.selectedIndex = sel + 1;
+
+ for (i = columns[source].length - 2; i > 0; i--) {
+ if (columns[source][i][0] == down || columns[source][i + 1][0] == down) {
+ column = columns[source][i];
+ columns[source][i] = columns[source][i + 1];
+ columns[source][i + 1] = column;
+ }
+ }
+
+ resetHidden();
+}
--- /dev/null
+/**
+ * Provides the javascript for the manager.php script.
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ */
+
+var Gollem = {
+ toggleRow: function()
+ {
+ $$('table.striped tr').each(function(tr) {
+ var td = tr.select('TD');
+ tr.observe('mouseover', td.invoke.bind(td, 'addClassName', 'selected'));
+ tr.observe('mouseout', td.invoke.bind(td, 'removeClassName', 'selected'));
+ });
+ },
+
+ getChecked: function()
+ {
+ return this.getElements().findAll(function(e) {
+ return e.checked;
+ });
+ },
+
+ getElements: function()
+ {
+ return $('manager').getInputs(null, 'items[]');
+ },
+
+ getSelected: function()
+ {
+ return this.getChecked().pluck('value').join("\n");
+ },
+
+ getItemsArray: function()
+ {
+ var i = 0,
+ it = $('manager').getInputs(null, 'itemTypes[]');
+
+ return this.getElements().collect(function(m) {
+ return { c: m.checked, v: m.value, t: it[i++].value };
+ });
+ },
+
+ getSelectedFoldersList: function()
+ {
+ return this.getItemsArray().collect(function(i) {
+ return (i.c && i.t == '**dir') ? i.v : null;
+ }).compact().join("\n");
+ },
+
+ chooseAction: function(i)
+ {
+ var action = $F('action' + i);
+
+ switch (action) {
+ case 'paste_items':
+ $('actionID').setValue('paste_items');
+ $('manager').submit();
+ break;
+
+ default:
+ if (!this.getChecked().size()) {
+ alert(GollemText.select_item);
+ break;
+ }
+ switch (action) {
+ case 'rename_items':
+ this.renameItems();
+ break;
+
+ case 'delete_items':
+ this.deleteItems();
+ break;
+
+ case 'chmod_modify':
+ $('attributes').show();
+ break;
+
+ case 'cut_items':
+ $('actionID').setValue('cut_items');
+ $('manager').submit();
+ break;
+
+ case 'copy_items':
+ $('actionID').setValue('copy_items');
+ $('manager').submit();
+ break;
+ }
+ break;
+ }
+ },
+
+ changeDirectory: function(e)
+ {
+ this._prepPopup('changeDirectory', e.element());
+ $('cdfrm_fname').focus();
+ e.stop();
+ },
+
+ createFolder: function(e)
+ {
+ this._prepPopup('createFolder', e.element());
+ $('createfrm_fname').focus();
+ e.stop();
+ },
+
+ _prepPopup: function(elt, elt2)
+ {
+ this.getChecked().each(function(e) {
+ e.checked = false;
+ });
+
+ $(elt).clonePosition(elt2, { setWidth: false, setHeight: false, offsetTop: elt2.getHeight() }).show();
+ },
+
+ renameItems: function()
+ {
+ var c = this.getChecked();
+ if (c.size()) {
+ c[0].checked = false;
+ $('rename').show();
+ $('renamefrm_oldname').setValue(c[0].value);
+ $('renamefrm_newname').setValue(c[0].value).focus();
+ }
+ },
+
+ deleteItems: function()
+ {
+ var cont = true, sf;
+
+ if (window.confirm(GollemText.delete_confirm_1 + '\n' + this.getSelected() + '\n' + GollemText.delete_confirm_2)) {
+ if (warn_recursive) {
+ sf = this.getSelectedFoldersList();
+ if (!sf.empty() &&
+ !window.confirm(GollemText.delete_recurs_1 + '\n' + sf + '\n' + GollemText.delete_recurs_2)) {
+ cont = false;
+ }
+ }
+ } else {
+ cont = false;
+ }
+
+ if (cont) {
+ $('actionID').setValue('delete_items');
+ $('manager').submit();
+ }
+ },
+
+ toggleSelection: function()
+ {
+ var e = this.getElements(),
+ checked = (this.getChecked().size() != e.length);
+ e.each(function(f) {
+ f.checked = checked;
+ });
+ },
+
+ createFolderOK: function()
+ {
+ $('createFolder').hide();
+ if ($F('createfrm_fname')) {
+ $('new_folder').setValue($F('createfrm_fname'));
+ $('actionID').setValue('create_folder');
+ $('manager').submit();
+ }
+ },
+
+ createFolderKeyCheck: function(e)
+ {
+ switch (e.keyCode) {
+ case Event.KEY_ESC:
+ this.createFolderCancel();
+ return false;
+
+ case EVENT.KEY_RETURN:
+ this.createFolderOK();
+ return false;
+ }
+ return true;
+ },
+
+ createFolderCancel: function()
+ {
+ $('createFolder').hide();
+ $('createfrm').reset();
+ },
+
+ chmodCancel: function()
+ {
+ $('attributes').hide();
+ $('chmodfrm').reset();
+ },
+
+ chmodSave: function()
+ {
+ var all = group = owner = 0;
+
+ $('chmodfrm').getElements().each(function(e) {
+ if (e.name == "owner[]" && e.checked) {
+ owner |= e.value;
+ } else if (e.name == "group[]" && e.checked) {
+ group |= e.value;
+ } else if (e.name == "all[]" && e.checked) {
+ all |= e.value;
+ }
+ });
+
+ $('attributes').hide();
+
+ $('chmod').setValue("0" + owner + "" + group + "" + all);
+ $('actionID').setValue('chmod_modify');
+ $('manager').submit();
+ },
+
+ renameOK: function()
+ {
+ var c = this.getChecked(),
+ newname = $F('renamefrm_newname'),
+ newNames = $F('new_names'),
+ oldname = $F('renamefrm_oldname'),
+ oldNames = $F('old_names');
+
+ if (newname && newname != oldname) {
+ newNames += "|" + newname;
+ oldNames += "|" + oldname;
+ }
+
+ if (newNames.startsWith("|")) {
+ newNames = newNames.substring(1);
+ }
+ if (oldNames.startsWith("|")) {
+ oldNames = oldNames.substring(1);
+ }
+
+ $('new_names').setValue(newNames);
+ $('old_names').setValue(oldNames);
+
+ if (c.size()) {
+ c[0].checked = false;
+ found = true;
+ $('rename').show();
+ $F(c[0]).focus();
+ } else {
+ $('actionID').setValue('rename_items');
+ $('manager').submit();
+ }
+
+ return false;
+ },
+
+ renameCancel: function()
+ {
+ $('new_names', 'old_names').invoke('setValue', '');
+ $('rename').hide();
+ },
+
+ renameKeyCheck: function(e)
+ {
+ switch (e.keyCode) {
+ case Event.KEY_ESC:
+ this.renameCancel();
+ return false;
+
+ case EVENT.KEY_RETURN:
+ this.renameOK();
+ return false;
+ }
+ return true;
+ },
+
+ changeDirectoryOK: function()
+ {
+ $('changeDirectory').hide();
+ if ($F('cdfrm_fname')) {
+ $('dir').setValue($F('cdfrm_fname'));
+ $('manager').submit();
+ }
+ },
+
+ changeDirectoryKeyCheck: function(e)
+ {
+ switch (e.keyCode) {
+ case Event.KEY_ESC:
+ this.changeDirectoryCancel();
+ return false;
+
+ case EVENT.KEY_RETURN:
+ this.changeDirectoryOK();
+ return false;
+ }
+ return true;
+ },
+
+ changeDirectoryCancel: function()
+ {
+ $('changeDirectory').hide();
+ $('cdfrm').reset();
+ },
+
+ uploadFields: function()
+ {
+ return $('manager').getInputs('file').collect(function(m) {
+ return (m.name.substr(0, 12) == 'file_upload_') ? m : null;
+ }).compact();
+ },
+
+ uploadFile: function()
+ {
+ if (this.uploadsExist()) {
+ $('actionID').setValue('upload_file');
+ $('manager').submit();
+ }
+ },
+
+ applyFilter: function()
+ {
+ $('manager').submit();
+ },
+
+ clearFilter: function()
+ {
+ $('filter').setValue('');
+ this.applyFilter();
+ },
+
+ uploadsExist: function()
+ {
+ if (GollemVar.empty_input ||
+ this.uploadFields().find(function(f) { return $F(f); })) {
+ return true;
+ }
+ alert(GollemText.specify_upload);
+ $('file_upload_1').focus();
+ return false;
+ },
+
+ uploadChanged: function()
+ {
+ if (GollemVar.empty_input) {
+ return;
+ }
+
+ var file, lastRow,
+ fields = this.uploadFields(),
+ usedFields = fields.findAll(function(f) { return $F(f).length; }).length;
+
+ if (usedFields == fields.length) {
+ lastRow = $('upload_row_' + usedFields);
+ if (lastRow) {
+ file = new Element('INPUT', { type: 'file', name: 'file_upload_' + (usedFields + 1), size: 25 });
+ lastRow.insert({ after:
+ new Element('DIV', { id: 'upload_row_' + (usedFields + 1) }).insert(
+ new Element('STRONG').insert(GollemText.file + ' ' + (usedFields + 1) + ':')
+ ).insert(' ').insert(file)
+ });
+ file.observe('change', this.uploadChanged.bind(this));
+ }
+ }
+ },
+
+ doPrefsUpdate: function(column, sortDown)
+ {
+ try {
+ new Ajax.Request(GollemVar.prefs_api, { parameters: { app: 'gollem', pref: 'sortby', value: column.substring(1) } });
+ new Ajax.Request(GollemVar.prefs_api, { parameters: { app: 'gollem', pref: 'sortdir', value: sortDown } });
+ } catch (e) {}
+ }
+};
+
+function table_sortCallback(tableId, column, sortDown)
+{
+ if (Gollem.prefs_update_timeout) {
+ window.clearTimeout(Gollem.prefs_update_timeout);
+ }
+ Gollem.prefs_update_timeout = Gollem.doPrefsUpdate.bind(this, column, sortDown).delay(0.3);
+}
+
+document.observe('dom:loaded', function() {
+ var tmp;
+ Gollem.toggleRow()
+ if (tmp = $('createfolder')) {
+ tmp.observe('click', Gollem.createFolder.bindAsEventListener(Gollem));
+ }
+ if (tmp = $('changefolder')) {
+ tmp.observe('click', Gollem.changeDirectory.bindAsEventListener(Gollem));
+ }
+});
--- /dev/null
+/**
+ * Provides the javascript for the selectlist.php script.
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ */
+function returnID()
+{
+ var field = parent.opener.document[formid].selectlist_selectid, field2 = parent.opener.document[formid].actionID;
+
+ if (parent.opener.closed || !field || !field2) {
+ alert(GollemText.opener_window);
+ window.close();
+ return;
+ }
+
+ field.value = cacheid;
+ field2.value = 'selectlist_process';
+
+ parent.opener.document[formid].submit();
+ window.close();
+}
+++ /dev/null
-/**
- * Provides the javascript for the gollem column select preferences page.
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- */
-
-var columns = [];
-
-function selectSource()
-{
- var f = document.prefs;
- var fieldString = '';
-
- while (f.unselected_columns.length > 1) {
- f.unselected_columns.options[f.unselected_columns.length - 1] = null;
- }
- while (f.selected_columns.length > 1) {
- f.selected_columns.options[f.selected_columns.length - 1] = null;
- }
-
- if (f.source.selectedIndex < 1) {
- return;
- }
- var source = f.source.selectedIndex - 1;
-
- var selected = [];
- var unselected = [];
- for (var i = 1; i < columns[source].length; i++) {
- if (columns[source][i][2]) {
- selected[columns[source][i][3]] = [columns[source][i][1], columns[source][i][0]];
- } else {
- unselected[unselected.length] = [columns[source][i][1], columns[source][i][0]];
- }
- }
- for (i = 0; i < selected.length; i++) {
- f.selected_columns.options[i + 1] = new Option(selected[i][0], selected[i][1]);
- }
- for (i = 0; i < unselected.length; i++) {
- f.unselected_columns.options[i + 1] = new Option(unselected[i][0], unselected[i][1]);
- }
-}
-
-function deselectHeaders()
-{
- document.prefs.unselected_columns[0].selected = false;
- document.prefs.selected_columns[0].selected = false;
-}
-
-function resetHidden()
-{
- var tmp = '';
- for (var i = 0; i < columns.length; i++) {
- if (i > 0) {
- tmp += '\n';
- }
- tmp += columns[i][0];
- for (var j = 1; j < columns[i].length; j++) {
- if (columns[i][j][2]) {
- tmp += '\t' + columns[i][j][0];
- }
- }
- }
- document.prefs.columns.value = tmp;
-}
-
-function addColumn()
-{
- var f = document.prefs;
- var source = f.source.selectedIndex - 1;
-
- for (i = 1; i < f.unselected_columns.length; i++) {
- if (f.unselected_columns[i].selected) {
- for (var j = 1; j < columns[source].length; j++) {
- if (columns[source][j][0] == f.unselected_columns[i].value) {
- columns[source][j][2] = true;
- }
- }
- f.selected_columns[f.selected_columns.length] = new Option(f.unselected_columns[i].text, f.unselected_columns[i].value);
- f.unselected_columns[i] = null;
- i--;
- }
- }
-
- resetHidden();
-}
-
-function removeColumn()
-{
- var f = document.prefs;
- var source = f.source.selectedIndex - 1;
-
- for (i = 1; i < f.selected_columns.length; i++) {
- if (f.selected_columns[i].selected) {
- for (var j = 1; j < columns[source].length; j++) {
- if (columns[source][j][0] == f.selected_columns[i].value) {
- columns[source][j][2] = false;
- }
- }
- f.unselected_columns[f.unselected_columns.length] = new Option(f.selected_columns[i].text, f.selected_columns[i].value)
- f.selected_columns[i] = null;
- i--;
- }
- }
-
- resetHidden();
-}
-
-function moveColumnUp()
-{
- var f = document.prefs;
- var sel = f.selected_columns.selectedIndex;
- var source = f.source.selectedIndex - 1;
-
- if (sel <= 1 || f.selected_columns.length <= 2) return;
-
- // deselect everything but the first selected item
- f.selected_columns.selectedIndex = sel;
- var up = f.selected_columns[sel].value;
-
- tmp = [];
- for (i = 1; i < f.selected_columns.length; i++) {
- tmp[i - 1] = new Option(f.selected_columns[i].text, f.selected_columns[i].value)
- }
-
- for (i = 0; i < tmp.length; i++) {
- if (i + 1 == sel - 1) {
- f.selected_columns[i + 1] = tmp[i + 1];
- } else if (i + 1 == sel) {
- f.selected_columns[i + 1] = tmp[i - 1];
- } else {
- f.selected_columns[i + 1] = tmp[i];
- }
- }
-
- f.selected_columns.selectedIndex = sel - 1;
-
- for (i = 2; i < columns[source].length - 1; i++) {
- if (columns[source][i][0] == up) {
- column = columns[source][i];
- columns[source][i] = columns[source][i - 1];
- columns[source][i - 1] = column;
- }
- }
-
- resetHidden();
-}
-
-function moveColumnDown()
-{
- var f = document.prefs;
- var sel = f.selected_columns.selectedIndex;
- var source = f.source.selectedIndex - 1;
-
- if (sel == -1 || f.selected_columns.length <= 2 || sel == f.selected_columns.length - 1) return;
-
- // deselect everything but the first selected item
- f.selected_columns.selectedIndex = sel;
- var down = f.selected_columns[sel].value;
-
- tmp = [];
- for (i = 1; i < f.selected_columns.length; i++) {
- tmp[i - 1] = new Option(f.selected_columns[i].text, f.selected_columns[i].value)
- }
-
- for (i = 0; i < tmp.length; i++) {
- if (i + 1 == sel) {
- f.selected_columns[i + 1] = tmp[i + 1];
- } else if (i + 1 == sel + 1) {
- f.selected_columns[i + 1] = tmp[i - 1];
- } else {
- f.selected_columns[i + 1] = tmp[i];
- }
- }
-
- f.selected_columns.selectedIndex = sel + 1;
-
- for (i = columns[source].length - 2; i > 0; i--) {
- if (columns[source][i][0] == down || columns[source][i + 1][0] == down) {
- column = columns[source][i];
- columns[source][i] = columns[source][i + 1];
- columns[source][i + 1] = column;
- }
- }
-
- resetHidden();
-}
+++ /dev/null
-/**
- * Provides the javascript for the manager.php script.
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- */
-
-var Gollem = {
- toggleRow: function()
- {
- $$('table.striped tr').each(function(tr) {
- var td = tr.select('TD');
- tr.observe('mouseover', td.invoke.bind(td, 'addClassName', 'selected'));
- tr.observe('mouseout', td.invoke.bind(td, 'removeClassName', 'selected'));
- });
- },
-
- getChecked: function()
- {
- return this.getElements().findAll(function(e) {
- return e.checked;
- });
- },
-
- getElements: function()
- {
- return $('manager').getInputs(null, 'items[]');
- },
-
- getSelected: function()
- {
- return this.getChecked().pluck('value').join("\n");
- },
-
- getItemsArray: function()
- {
- var i = 0,
- it = $('manager').getInputs(null, 'itemTypes[]');
-
- return this.getElements().collect(function(m) {
- return { c: m.checked, v: m.value, t: it[i++].value };
- });
- },
-
- getSelectedFoldersList: function()
- {
- return this.getItemsArray().collect(function(i) {
- return (i.c && i.t == '**dir') ? i.v : null;
- }).compact().join("\n");
- },
-
- chooseAction: function(i)
- {
- var action = $F('action' + i);
-
- switch (action) {
- case 'paste_items':
- $('actionID').setValue('paste_items');
- $('manager').submit();
- break;
-
- default:
- if (!this.getChecked().size()) {
- alert(GollemText.select_item);
- break;
- }
- switch (action) {
- case 'rename_items':
- this.renameItems();
- break;
-
- case 'delete_items':
- this.deleteItems();
- break;
-
- case 'chmod_modify':
- $('attributes').show();
- break;
-
- case 'cut_items':
- $('actionID').setValue('cut_items');
- $('manager').submit();
- break;
-
- case 'copy_items':
- $('actionID').setValue('copy_items');
- $('manager').submit();
- break;
- }
- break;
- }
- },
-
- changeDirectory: function(e)
- {
- this._prepPopup('changeDirectory', e.element());
- $('cdfrm_fname').focus();
- e.stop();
- },
-
- createFolder: function(e)
- {
- this._prepPopup('createFolder', e.element());
- $('createfrm_fname').focus();
- e.stop();
- },
-
- _prepPopup: function(elt, elt2)
- {
- this.getChecked().each(function(e) {
- e.checked = false;
- });
-
- $(elt).clonePosition(elt2, { setWidth: false, setHeight: false, offsetTop: elt2.getHeight() }).show();
- },
-
- renameItems: function()
- {
- var c = this.getChecked();
- if (c.size()) {
- c[0].checked = false;
- $('rename').show();
- $('renamefrm_oldname').setValue(c[0].value);
- $('renamefrm_newname').setValue(c[0].value).focus();
- }
- },
-
- deleteItems: function()
- {
- var cont = true, sf;
-
- if (window.confirm(GollemText.delete_confirm_1 + '\n' + this.getSelected() + '\n' + GollemText.delete_confirm_2)) {
- if (warn_recursive) {
- sf = this.getSelectedFoldersList();
- if (!sf.empty() &&
- !window.confirm(GollemText.delete_recurs_1 + '\n' + sf + '\n' + GollemText.delete_recurs_2)) {
- cont = false;
- }
- }
- } else {
- cont = false;
- }
-
- if (cont) {
- $('actionID').setValue('delete_items');
- $('manager').submit();
- }
- },
-
- toggleSelection: function()
- {
- var e = this.getElements(),
- checked = (this.getChecked().size() != e.length);
- e.each(function(f) {
- f.checked = checked;
- });
- },
-
- createFolderOK: function()
- {
- $('createFolder').hide();
- if ($F('createfrm_fname')) {
- $('new_folder').setValue($F('createfrm_fname'));
- $('actionID').setValue('create_folder');
- $('manager').submit();
- }
- },
-
- createFolderKeyCheck: function(e)
- {
- switch (e.keyCode) {
- case Event.KEY_ESC:
- this.createFolderCancel();
- return false;
-
- case EVENT.KEY_RETURN:
- this.createFolderOK();
- return false;
- }
- return true;
- },
-
- createFolderCancel: function()
- {
- $('createFolder').hide();
- $('createfrm').reset();
- },
-
- chmodCancel: function()
- {
- $('attributes').hide();
- $('chmodfrm').reset();
- },
-
- chmodSave: function()
- {
- var all = group = owner = 0;
-
- $('chmodfrm').getElements().each(function(e) {
- if (e.name == "owner[]" && e.checked) {
- owner |= e.value;
- } else if (e.name == "group[]" && e.checked) {
- group |= e.value;
- } else if (e.name == "all[]" && e.checked) {
- all |= e.value;
- }
- });
-
- $('attributes').hide();
-
- $('chmod').setValue("0" + owner + "" + group + "" + all);
- $('actionID').setValue('chmod_modify');
- $('manager').submit();
- },
-
- renameOK: function()
- {
- var c = this.getChecked(),
- newname = $F('renamefrm_newname'),
- newNames = $F('new_names'),
- oldname = $F('renamefrm_oldname'),
- oldNames = $F('old_names');
-
- if (newname && newname != oldname) {
- newNames += "|" + newname;
- oldNames += "|" + oldname;
- }
-
- if (newNames.startsWith("|")) {
- newNames = newNames.substring(1);
- }
- if (oldNames.startsWith("|")) {
- oldNames = oldNames.substring(1);
- }
-
- $('new_names').setValue(newNames);
- $('old_names').setValue(oldNames);
-
- if (c.size()) {
- c[0].checked = false;
- found = true;
- $('rename').show();
- $F(c[0]).focus();
- } else {
- $('actionID').setValue('rename_items');
- $('manager').submit();
- }
-
- return false;
- },
-
- renameCancel: function()
- {
- $('new_names', 'old_names').invoke('setValue', '');
- $('rename').hide();
- },
-
- renameKeyCheck: function(e)
- {
- switch (e.keyCode) {
- case Event.KEY_ESC:
- this.renameCancel();
- return false;
-
- case EVENT.KEY_RETURN:
- this.renameOK();
- return false;
- }
- return true;
- },
-
- changeDirectoryOK: function()
- {
- $('changeDirectory').hide();
- if ($F('cdfrm_fname')) {
- $('dir').setValue($F('cdfrm_fname'));
- $('manager').submit();
- }
- },
-
- changeDirectoryKeyCheck: function(e)
- {
- switch (e.keyCode) {
- case Event.KEY_ESC:
- this.changeDirectoryCancel();
- return false;
-
- case EVENT.KEY_RETURN:
- this.changeDirectoryOK();
- return false;
- }
- return true;
- },
-
- changeDirectoryCancel: function()
- {
- $('changeDirectory').hide();
- $('cdfrm').reset();
- },
-
- uploadFields: function()
- {
- return $('manager').getInputs('file').collect(function(m) {
- return (m.name.substr(0, 12) == 'file_upload_') ? m : null;
- }).compact();
- },
-
- uploadFile: function()
- {
- if (this.uploadsExist()) {
- $('actionID').setValue('upload_file');
- $('manager').submit();
- }
- },
-
- applyFilter: function()
- {
- $('manager').submit();
- },
-
- clearFilter: function()
- {
- $('filter').setValue('');
- this.applyFilter();
- },
-
- uploadsExist: function()
- {
- if (GollemVar.empty_input ||
- this.uploadFields().find(function(f) { return $F(f); })) {
- return true;
- }
- alert(GollemText.specify_upload);
- $('file_upload_1').focus();
- return false;
- },
-
- uploadChanged: function()
- {
- if (GollemVar.empty_input) {
- return;
- }
-
- var file, lastRow,
- fields = this.uploadFields(),
- usedFields = fields.findAll(function(f) { return $F(f).length; }).length;
-
- if (usedFields == fields.length) {
- lastRow = $('upload_row_' + usedFields);
- if (lastRow) {
- file = new Element('INPUT', { type: 'file', name: 'file_upload_' + (usedFields + 1), size: 25 });
- lastRow.insert({ after:
- new Element('DIV', { id: 'upload_row_' + (usedFields + 1) }).insert(
- new Element('STRONG').insert(GollemText.file + ' ' + (usedFields + 1) + ':')
- ).insert(' ').insert(file)
- });
- file.observe('change', this.uploadChanged.bind(this));
- }
- }
- },
-
- doPrefsUpdate: function(column, sortDown)
- {
- try {
- new Ajax.Request(GollemVar.prefs_api, { parameters: { app: 'gollem', pref: 'sortby', value: column.substring(1) } });
- new Ajax.Request(GollemVar.prefs_api, { parameters: { app: 'gollem', pref: 'sortdir', value: sortDown } });
- } catch (e) {}
- }
-};
-
-function table_sortCallback(tableId, column, sortDown)
-{
- if (Gollem.prefs_update_timeout) {
- window.clearTimeout(Gollem.prefs_update_timeout);
- }
- Gollem.prefs_update_timeout = Gollem.doPrefsUpdate.bind(this, column, sortDown).delay(0.3);
-}
-
-document.observe('dom:loaded', function() {
- var tmp;
- Gollem.toggleRow()
- if (tmp = $('createfolder')) {
- tmp.observe('click', Gollem.createFolder.bindAsEventListener(Gollem));
- }
- if (tmp = $('changefolder')) {
- tmp.observe('click', Gollem.changeDirectory.bindAsEventListener(Gollem));
- }
-});
+++ /dev/null
-/**
- * Provides the javascript for the selectlist.php script.
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- */
-function returnID()
-{
- var field = parent.opener.document[formid].selectlist_selectid, field2 = parent.opener.document[formid].actionID;
-
- if (parent.opener.closed || !field || !field2) {
- alert(GollemText.opener_window);
- window.close();
- return;
- }
-
- field.value = cacheid;
- field2.value = 'selectlist_process';
-
- parent.opener.document[formid].submit();
- window.close();
-}
the `Firebug`_ extension installed in order to better track javascript
errors - it is what the developers use and makes deciphering error codes and
error line numbers much easier. It is also recommended to set the ``debug``
-parameter in ``imp/conf/conf.php`` to ``true`` (no quotes). Next you will
-want to turn off javascript caching, if on, in ``imp/conf/conf.php``.
-Finally, you need to change ``horde/conf/registry.php`` to serve the
-javascript files from the ``js/src/`` directory rather than the ``js/``
-directory (we compress javascript files to reduce network load, but this
-results in all javascript errors occurring on "line 1" which is not very
-useful to diagnose problems).
+parameter in ``imp/conf/conf.php`` to ``true`` (no quotes). You will also
+want to turn off javascript caching, if on, in ``horde/conf/conf.php``.
If you do find a javascript error, it would be great if you could fix the
issue and provide a patch :) Absent that, before reporting to the mailing
--- /dev/null
+/**
+ * ContextSensitive: a library for generating context-sensitive content on
+ * HTML elements. It will take over the click/oncontextmenu functions for the
+ * document, and works only where these are possible to override. It allows
+ * contextmenus to be created via both a left and right mouse click.
+ *
+ * Requires prototypejs 1.6+ and scriptaculous 1.8+ (effects.js only).
+ *
+ * Original code by Havard Eide (http://eide.org/) released under the MIT
+ * license.
+ *
+ * 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 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.
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Michael Slusarz <slusarz@horde.org>
+ */
+
+var ContextSensitive = Class.create({
+
+ initialize: function(opts)
+ {
+ this.baseelt = null;
+ this.current = [];
+ this.elements = $H();
+ this.opts = opts || {};
+ this.submenus = $H();
+ this.triggers = [];
+
+ document.observe('contextmenu', this._rightClickHandler.bindAsEventListener(this));
+ document.observe('click', this._leftClickHandler.bindAsEventListener(this));
+ document.observe(Prototype.Browser.Gecko ? 'DOMMouseScroll' : 'mousescroll', this.close.bind(this));
+ },
+
+ /**
+ * Elements are of type ContextSensitive.Element.
+ */
+ addElement: function(id, target, opts)
+ {
+ var left = Boolean(opts.left);
+ if (id && !this.validElement(id, left)) {
+ this.elements.set(id + Number(left), new ContextSensitive.Element(id, target, opts));
+ }
+ },
+
+ /**
+ * Remove a registered element.
+ */
+ removeElement: function(id)
+ {
+ this.elements.unset(id + '0');
+ this.elements.unset(id + '1');
+ },
+
+ /**
+ * Hide the currently displayed element(s).
+ */
+ close: function()
+ {
+ this._closeMenu(0, true);
+ },
+
+ /**
+ * Close all menus below a specified level.
+ */
+ _closeMenu: function(idx, immediate)
+ {
+ if (this.current.size()) {
+ this.current.splice(idx, this.current.size() - idx).each(function(s) {
+ // Fade-out on final display.
+ if (!immediate && idx == 0) {
+ Effect.Fade(s, { duration: 0.15 });
+ } else {
+ $(s).hide();
+ }
+ });
+
+ this.triggers.splice(idx, this.triggers.size() - idx).each(function(s) {
+ $(s).removeClassName('contextHover');
+ });
+
+ if (idx == 0) {
+ this.baseelt = null;
+ }
+ }
+ },
+
+ /**
+ * Returns the current displayed menu element ID, if any. If more than one
+ * submenu is open, returns the last ID opened.
+ */
+ currentmenu: function()
+ {
+ return this.current.last();
+ },
+
+ /**
+ * Get a valid element (the ones that can be right-clicked) based
+ * on a element ID.
+ */
+ validElement: function(id, left)
+ {
+ return this.elements.get(id + Number(Boolean(left)));
+ },
+
+ /**
+ * Set the disabled flag of an event.
+ */
+ disable: function(id, left, disable)
+ {
+ var e = this.validElement(id, left);
+ if (e) {
+ e.disable = disable;
+ }
+ },
+
+ /**
+ * Called when a left click event occurs. Will return before the
+ * element is closed if we click on an element inside of it.
+ */
+ _leftClickHandler: function(e)
+ {
+ var base, elt, elt_up, trigger;
+
+ // Check for a right click. FF on Linux triggers an onclick event even
+ // w/a right click, so disregard.
+ if (e.isRightClick()) {
+ return;
+ }
+
+ // Check for click in open contextmenu.
+ if (this.current.size()) {
+ elt = e.element();
+ if (!elt.match('A')) {
+ elt = elt.up('A');
+ if (!elt) {
+ this._rightClickHandler(e, true);
+ return;
+ }
+ }
+ elt_up = elt.up();
+
+ if (elt_up && elt_up.hasClassName('contextMenu')) {
+ e.stop();
+
+ if (elt.hasClassName('contextSubmenu') &&
+ elt_up.readAttribute('id') != this.currentmenu()) {
+ this._closeMenu(this.current.indexOf(elt.readAttribute('id')));
+ } else {
+ base = this.baseelt;
+ trigger = this.triggers.last();
+ this.close();
+ if (this.opts.onClick) {
+ this.opts.onClick(elt, base, trigger);
+ }
+ }
+ return;
+ }
+ }
+
+ // Check if the mouseclick is registered to an element now.
+ this._rightClickHandler(e, true);
+ },
+
+ /**
+ * Called when a right click event occurs.
+ */
+ _rightClickHandler: function(e, left)
+ {
+ if (this.trigger(e.element(), left, e.pointerX(), e.pointerY())) {
+ e.stop();
+ };
+ },
+
+ /**
+ * Display context menu if valid element has been activated.
+ */
+ trigger: function(target, leftclick, x, y)
+ {
+ var ctx, el, el_id, offset, offsets, voffsets;
+
+ [ target ].concat(target.ancestors()).find(function(n) {
+ ctx = this.validElement(n.id, leftclick);
+ return ctx;
+ }, this);
+
+ // Return if event not found or event is disabled.
+ if (!ctx || ctx.disable) {
+ this.close();
+ return false;
+ }
+
+ // Try to retrieve the context-sensitive element we want to
+ // display. If we can't find it we just return.
+ el = $(ctx.ctx);
+ if (!el) {
+ this.close();
+ return false;
+ }
+
+ el_id = el.readAttribute('id');
+ if (leftclick && el_id == this.currentmenu()) {
+ return false;
+ }
+
+ this.close();
+
+ // Register the element that was clicked on.
+ this.baseelt = target;
+
+ offset = ctx.opts.offset;
+ if (!offset && (Object.isUndefined(x) || Object.isUndefined(y))) {
+ offset = target.readAttribute('id');
+ }
+ offset = $(offset);
+
+ if (offset) {
+ offsets = offset.viewportOffset();
+ voffsets = document.viewport.getScrollOffsets();
+ x = offsets[0] + voffsets.left;
+ y = offsets[1] + offset.getHeight() + voffsets.top;
+ }
+
+ this._displayMenu(el, x, y);
+ this.triggers.push(el_id);
+
+ return true;
+ },
+
+ /**
+ * Display the [sub]menu on the screen.
+ */
+ _displayMenu: function(elt, x, y)
+ {
+ // Get window/element dimensions
+ var id = elt.readAttribute('id'),
+ size = elt.getDimensions(),
+ v = document.viewport.getDimensions();
+
+ // Make sure context window is entirely on screen
+ if ((y + size.height) > v.height) {
+ y = v.height - size.height - 10;
+ }
+ if ((x + size.width) > v.width) {
+ x = v.width - size.width - 10;
+ }
+
+ if (this.opts.onShow) {
+ this.opts.onShow(id, this.baseelt);
+ }
+
+ elt.setStyle({ left: x + 'px', top: y + 'px' })
+
+ if (this.current.size()) {
+ elt.show();
+ } else {
+ // Fade-in on initial display.
+ Effect.Appear(elt, { duration: 0.15 });
+ }
+
+ this.current.push(id);
+ },
+
+ /**
+ * Add a submenu to an existing menu.
+ */
+ addSubMenu: function(id, submenu)
+ {
+ if (!this.submenus.get(id)) {
+ if (!this.submenus.size()) {
+ document.observe('mouseover', this._mouseoverHandler.bindAsEventListener(this));
+ }
+ this.submenus.set(id, submenu);
+ $(submenu).addClassName('contextMenu');
+ $(id).addClassName('contextSubmenu');
+ }
+ },
+
+ /**
+ * Mouseover DOM Event handler.
+ */
+ _mouseoverHandler: function(e)
+ {
+ if (!this.current.size()) {
+ return;
+ }
+
+ var cm = this.currentmenu(),
+ elt = e.element(),
+ elt_up = elt.up(),
+ id = elt.readAttribute('id'),
+ id_div, offsets, sub, voffsets, x, y;
+
+ if (elt_up == document) {
+ return;
+ }
+
+ id_div = elt_up.readAttribute('id');
+
+ if (elt.hasClassName('contextSubmenu')) {
+ sub = this.submenus.get(id);
+ if (sub != cm || this.currentmenu() != id) {
+ if (id_div != cm) {
+ this._closeMenu(this.current.indexOf(id_div) + 1);
+ }
+
+ offsets = elt.viewportOffset();
+ voffsets = document.viewport.getScrollOffsets();
+ x = offsets[0] + voffsets.left + elt.getWidth();
+ y = offsets[1] + voffsets.top;
+ this._displayMenu($(sub), x, y, id);
+ this.triggers.push(id);
+ elt.addClassName('contextHover');
+ }
+ } else if ((this.current.size() > 1) &&
+ elt_up.hasClassName('contextMenu') &&
+ id_div != cm) {
+ this._closeMenu(this.current.indexOf(id));
+ }
+ }
+
+});
+
+ContextSensitive.Element = Class.create({
+
+ // opts: 'left' -> monitor left click; 'offset' -> id of element used to
+ // determine offset placement
+ initialize: function(id, target, opts)
+ {
+ this.id = id;
+ this.ctx = target;
+ this.opts = opts;
+ this.opts.left = Boolean(opts.left);
+ this.disable = false;
+
+ target = $(target);
+ if (target) {
+ target.addClassName('contextMenu');
+ }
+ }
+
+});
--- /dev/null
+/**
+ * DimpBase.js - Javascript used in the base DIMP page.
+ *
+ * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var DimpBase = {
+ // Vars used and defaulting to null/false:
+ // cfolderaction, folder, folderswitch, offset, pollPE, pp, sfolder,
+ // showunsub, uid, viewport
+ // message_list_template set via templates/javascript/mailbox.js
+ bcache: $H(),
+ cacheids: {},
+ lastrow: -1,
+ pivotrow: -1,
+ ppcache: {},
+ ppfifo: [],
+ tcache: {},
+
+ // Preview pane cache size is 20 entries. Given that a reasonable guess
+ // of an average e-mail size is 10 KB (including headers), also make
+ // an estimate that the JSON data size will be approx. 10 KB. 200 KB
+ // should be a fairly safe caching value for any recent browser.
+ ppcachesize: 20,
+
+ // Message selection functions
+
+ // vs = (ViewPort_Selection) A ViewPort_Selection object.
+ // opts = (object) Boolean options [delay, right]
+ _select: function(vs, opts)
+ {
+ var d = vs.get('rownum');
+ if (d.size() == 1) {
+ this.lastrow = this.pivotrow = d.first();
+ }
+
+ this.toggleButtons();
+
+ if ($('previewPane').visible()) {
+ if (opts.right) {
+ this.clearPreviewPane();
+ } else {
+ if (opts.delay) {
+ (this.bcache.get('initPP') || this.bcache.set('initPP', this.initPreviewPane.bind(this))).delay(opts.delay);
+ } else {
+ this.initPreviewPane();
+ }
+ }
+ }
+ },
+
+ // vs = (ViewPort_Selection) A ViewPort_Selection object.
+ // opts = (object) Boolean options [right]
+ _deselect: function(vs, opts)
+ {
+ var sel = this.viewport.getSelected(),
+ count = sel.size();
+ if (!count) {
+ this.lastrow = this.pivotrow = -1;
+ }
+
+ this.toggleButtons();
+ if (opts.right || !count) {
+ this.clearPreviewPane();
+ } else if ((count == 1) && $('previewPane').visible()) {
+ this.loadPreview(sel.get('dataob').first());
+ }
+ },
+
+ // id = (string) DOM ID
+ // opts = (Object) Boolean options [ctrl, right, shift]
+ msgSelect: function(id, opts)
+ {
+ var bounds,
+ row = this.viewport.createSelection('domid', id),
+ rownum = row.get('rownum').first(),
+ sel = this.isSelected('domid', id),
+ selcount = this.selectedCount();
+
+ this.lastrow = rownum;
+
+ // Some browsers need to stop the mousedown event before it propogates
+ // down to the browser level in order to prevent text selection on
+ // drag/drop actions. Clicking on a message should always lose focus
+ // from the search input, because the user may immediately start
+ // keyboard navigation after that. Thus, we need to ensure that a
+ // message click loses focus on the search input.
+ if ($('qsearch')) {
+ $('qsearch_input').blur();
+ }
+
+ if (opts.shift) {
+ if (selcount) {
+ if (!sel || selcount != 1) {
+ bounds = [ rownum, this.pivotrow ];
+ this.viewport.select($A($R(bounds.min(), bounds.max())), { range: true });
+ }
+ return;
+ }
+ } else if (opts.ctrl) {
+ this.pivotrow = rownum;
+ if (sel) {
+ this.viewport.deselect(row, { right: opts.right });
+ return;
+ } else if (opts.right || selcount) {
+ this.viewport.select(row, { add: true, right: opts.right });
+ return;
+ }
+ }
+
+ this.viewport.select(row, { right: opts.right });
+ },
+
+ selectAll: function()
+ {
+ this.viewport.select($A($R(1, this.viewport.getMetaData('total_rows'))), { range: true });
+ },
+
+ isSelected: function(format, data)
+ {
+ return this.viewport.getSelected().contains(format, data);
+ },
+
+ selectedCount: function()
+ {
+ return (this.viewport) ? this.viewport.getSelected().size() : 0;
+ },
+
+ resetSelected: function()
+ {
+ if (this.viewport) {
+ this.viewport.deselect(this.viewport.getSelected(), { clearall: true });
+ }
+ this.toggleButtons();
+ this.clearPreviewPane();
+ },
+
+ // num = (integer) See absolute.
+ // absolute = Is num an absolute row number - from 1 -> page_size (true) -
+ // or a relative change from the current selected value (false)
+ // If no current selected value, the first message in the
+ // current viewport is selected.
+ moveSelected: function(num, absolute)
+ {
+ var curr, curr_row, row, row_data, sel;
+
+ if (absolute) {
+ if (!this.viewport.getMetaData('total_rows')) {
+ return;
+ }
+ curr = num;
+ } else {
+ if (num == 0) {
+ return;
+ }
+
+ sel = this.viewport.getSelected();
+ switch (sel.size()) {
+ case 0:
+ curr = this.viewport.currentOffset();
+ curr += (num > 0) ? 1 : this.viewport.getPageSize('current');
+ break;
+
+ case 1:
+ curr_row = sel.get('dataob').first();
+ curr = curr_row.rownum + num;
+ break;
+
+ default:
+ sel = sel.get('rownum');
+ curr = (num > 0 ? sel.max() : sel.min()) + num;
+ break;
+ }
+ curr = (num > 0) ? Math.min(curr, this.viewport.getMetaData('total_rows')) : Math.max(curr, 1);
+ }
+
+ row = this.viewport.createSelection('rownum', curr);
+ if (row.size()) {
+ row_data = row.get('dataob').first();
+ if (!curr_row || row_data.imapuid != curr_row.imapuid) {
+ this.viewport.scrollTo(row_data.rownum);
+ this.viewport.select(row, { delay: 0.3 });
+ }
+ } else {
+ this.offset = curr;
+ this.viewport.requestContentRefresh(curr - 1);
+ }
+ },
+ // End message selection functions
+
+ go: function(loc, data)
+ {
+ var app, f, separator;
+
+ /* If switching from options, we need to reload page to pick up any
+ * prefs changes. */
+ if (this.folder === null &&
+ loc != 'options' &&
+ $('appoptions') &&
+ $('appoptions').hasClassName('on')) {
+ return DimpCore.redirect(DIMP.conf.URI_DIMP + '#' + loc, true);
+ }
+
+ if (loc.startsWith('compose:')) {
+ return;
+ }
+
+ if (loc.startsWith('msg:')) {
+ separator = loc.indexOf(':', 4);
+ f = loc.substring(4, separator);
+ this.uid = loc.substring(separator + 1);
+ loc = 'folder:' + f;
+ // Now fall through to the 'folder:' check below.
+ }
+
+ if (loc.startsWith('folder:')) {
+ f = loc.substring(7);
+ if (this.folder != f || !$('dimpmain_folder').visible()) {
+ this.highlightSidebar(this.getFolderId(f));
+ if (!$('dimpmain_folder').visible()) {
+ $('dimpmain_portal').hide();
+ $('dimpmain_folder').show();
+ }
+ // This catches the refresh case - no need to re-add to history
+ if (!Object.isUndefined(this.folder)) {
+ this._addHistory(loc);
+ }
+ }
+ this.loadMailbox(f);
+ return;
+ }
+
+ this.folder = null;
+ $('dimpmain_folder').hide();
+ $('dimpmain_portal').update(DIMP.text.loading).show();
+
+ if (loc.startsWith('app:')) {
+ app = loc.substr(4);
+ if (app == 'imp') {
+ this.go('folder:INBOX');
+ return;
+ }
+ this.highlightSidebar('app' + app);
+ this._addHistory(loc, data);
+ if (data) {
+ this.iframeContent(loc, data);
+ } else if (DIMP.conf.app_urls[app]) {
+ this.iframeContent(loc, DIMP.conf.app_urls[app]);
+ }
+ return;
+ }
+
+ switch (loc) {
+ case 'portal':
+ this.highlightSidebar('appportal');
+ this._addHistory(loc);
+ DimpCore.setTitle(DIMP.text.portal);
+ DimpCore.doAction('ShowPortal', {}, null, this.bcache.get('portalC') || this.bcache.set('portalC', this._portalCallback.bind(this)));
+ break;
+
+ case 'options':
+ this.highlightSidebar('appoptions');
+ this._addHistory(loc);
+ DimpCore.setTitle(DIMP.text.prefs);
+ this.iframeContent(loc, DIMP.conf.URI_PREFS_IMP);
+ break;
+ }
+ },
+
+ _addHistory: function(loc, data)
+ {
+ if (Horde.dhtmlHistory.getCurrentLocation() != loc) {
+ Horde.dhtmlHistory.add(loc, data);
+ }
+ },
+
+ highlightSidebar: function(id)
+ {
+ // Folder bar may not be fully loaded yet.
+ if ($('foldersLoading').visible()) {
+ this.highlightSidebar.bind(this, id).defer();
+ return;
+ }
+
+ var curr = $('sidebarPanel').down('.on'),
+ elt = $(id);
+
+ if (!elt || curr == elt) {
+ return;
+ }
+
+ if (!elt.match('LI')) {
+ elt = elt.up();
+ if (!elt) {
+ return;
+ }
+ }
+
+ if (curr) {
+ curr.removeClassName('on');
+ }
+ elt.addClassName('on');
+
+ this._toggleSubFolder(elt, 'exp');
+ },
+
+ iframeContent: function(name, loc)
+ {
+ if (name === null) {
+ name = loc;
+ }
+
+ var container = $('dimpmain_portal'), iframe;
+ if (!container) {
+ DimpCore.showNotifications([ { type: 'horde.error', message: 'Bad portal!' } ]);
+ return;
+ }
+
+ iframe = new Element('IFRAME', { id: 'iframe' + name, className: 'iframe', frameBorder: 0, src: loc });
+ this._resizeIE6Iframe(iframe);
+ container.insert(iframe);
+ },
+
+ // r = ViewPort row data
+ msgWindow: function(r)
+ {
+ this.updateSeenUID(r, 1);
+ var url = DIMP.conf.URI_MESSAGE;
+ url += (url.include('?') ? '&' : '?') +
+ $H({ folder: r.view,
+ uid: Number(r.imapuid) }).toQueryString();
+ DimpCore.popupWindow(url, 'msgview' + r.view + r.imapuid);
+ },
+
+ composeMailbox: function(type)
+ {
+ var sel = this.viewport.getSelected();
+ if (!sel.size()) {
+ return;
+ }
+ sel.get('dataob').each(function(s) {
+ DimpCore.compose(type, { folder: s.view, uid: s.imapuid });
+ });
+ },
+
+ loadMailbox: function(f, opts)
+ {
+ opts = opts || {};
+
+ if (!this.viewport) {
+ this._createViewPort();
+ }
+
+ if (!opts.background) {
+ this.resetSelected();
+ this.quicksearchClear(true);
+
+ if (this.folder == f) {
+ return;
+ }
+
+ $('folderName').update(DIMP.text.loading);
+ $('msgHeader').update();
+ this.folderswitch = true;
+ this.folder = f;
+ }
+
+ this.viewport.loadView(f, this.uid ? { imapuid: Number(this.uid), view: f } : null, opts.background);
+ },
+
+ _createViewPort: function()
+ {
+ this.viewport = new ViewPort({
+ // Mandatory config
+ ajax_url: DIMP.conf.URI_AJAX + '/ViewPort',
+ content: 'msgList',
+ template: this.message_list_template,
+
+ // Optional config
+ ajax_opts: DimpCore.doActionOpts,
+ buffer_pages: DIMP.conf.buffer_pages,
+ content_class: 'msglist',
+ empty_msg: DIMP.text.vp_empty,
+ limit_factor: DIMP.conf.limit_factor,
+ page_size: DIMP.conf.splitbar_pos,
+ show_split_pane: DIMP.conf.preview_pref,
+ split_bar: 'splitBar',
+ split_pane: 'previewPane',
+ wait: DIMP.conf.viewport_wait,
+
+ // Callbacks
+ onAjaxRequest: function(id) {
+ var p = this.isSearch(id)
+ ? $H({
+ qsearch: $F('qsearch_input'),
+ qsearchmbox: this.sfolder
+ })
+ : $H();
+ return DimpCore.addRequestParams(p);
+ }.bind(this),
+ onAjaxResponse: DimpCore.doActionComplete.bind(DimpCore),
+ onCachedList: function(id) {
+ var tmp, vs;
+ if (!this.cacheids[id]) {
+ vs = this.viewport.getSelection(id);
+ if (!vs.size()) {
+ return '';
+ }
+
+ if (vs.getBuffer().getMetaData('search')) {
+ this.cacheids[id] = vs.get('uid').toJSON();
+ } else {
+ tmp = {};
+ tmp[id] = vs.get('uid').clone();
+ this.cacheids[id] = DimpCore.toRangeString(tmp);
+ }
+ }
+ return this.cacheids[id];
+ }.bind(this),
+ onCacheUpdate: function(id) {
+ delete this.cacheids[id];
+ }.bind(this),
+ onClear: function(r) {
+ r.each(this._removeMouseEvents.bind(this));
+ }.bind(this),
+ onContent: function(row) {
+ var bg, re, u,
+ thread = $H(this.viewport.getMetaData('thread')),
+ tsort = (this.viewport.getMetaData('sortby') == DIMP.conf.sortthread);
+
+ row.subjectdata = row.status = '';
+ row.subjecttitle = row.subject;
+
+ // Add thread graphics
+ if (tsort) {
+ u = thread.get(row.imapuid);
+ if (u) {
+ $R(0, u.length, true).each(function(i) {
+ var c = u.charAt(i);
+ if (!this.tcache[c]) {
+ this.tcache[c] = '<span class="threadImg threadImg' + c + '"></span>';
+ }
+ row.subjectdata += this.tcache[c];
+ }, this);
+ }
+ }
+
+ /* Generate the status flags. */
+ if (row.flag) {
+ row.flag.each(function(a) {
+ var ptr = DIMP.conf.flags[a];
+ if (ptr.p) {
+ if (!ptr.elt) {
+ /* Until text-overflow is supported on all
+ * browsers, need to truncate label text
+ * ourselves. */
+ ptr.elt = '<span class="' + ptr.c + '" title="' + ptr.l + '" style="background:' + ptr.b + '">' + ptr.l.truncate(10) + '</span>';
+ }
+ row.subjectdata += ptr.elt;
+ } else {
+ if (!ptr.elt) {
+ ptr.elt = '<div class="msgflags ' + ptr.c + '" title="' + ptr.l + '"></div>';
+ }
+ row.status += ptr.elt;
+
+ row.bg.push(ptr.c);
+
+ if (ptr.b) {
+ bg = ptr.b;
+ }
+ }
+ });
+ }
+
+ // Set bg
+ if (bg) {
+ row.style = 'background:' + bg;
+ }
+
+ // Check for search strings
+ if (this.isSearch()) {
+ re = new RegExp("(" + $F('qsearch_input') + ")", "i");
+ [ 'from', 'subject' ].each(function(h) {
+ row[h] = row[h].gsub(re, '<span class="qsearchMatch">#{1}</span>');
+ });
+ }
+
+ // If these fields are null, invalid string was scrubbed by
+ // JSON encode.
+ if (row.from === null) {
+ row.from = '[' + DIMP.text.badaddr + ']';
+ }
+ if (row.subject === null) {
+ row.subject = row.subjecttitle = '[' + DIMP.text.badsubject + ']';
+ }
+ }.bind(this),
+ onContentComplete: function(rows) {
+ var row, ssc, tmp,
+ l = this.viewport.getMetaData('label');
+
+ this.setMessageListTitle();
+ if (!this.isSearch()) {
+ this.setFolderLabel(this.folder, this.viewport.getMetaData('unseen') || 0);
+ }
+ this.updateTitle();
+
+ rows.each(function(row) {
+ // Add context menu
+ this._addMouseEvents({ id: row.domid, type: row.menutype });
+ new Drag(row.domid, this._msgDragConfig);
+ }, this);
+
+ if (this.uid) {
+ row = this.viewport.getSelection().search({ imapuid: { equal: [ this.uid ] }, view: { equal: [ this.folder ] } });
+ if (row.size()) {
+ this.viewport.scrollTo(row.get('rownum').first());
+ this.viewport.select(row);
+ }
+ } else if (this.offset) {
+ this.viewport.select(this.viewport.createSelection('rownum', this.offset));
+ }
+ this.offset = this.uid = null;
+
+ // 'label' will not be set if there has been an error
+ // retrieving data from the server.
+ l = this.viewport.getMetaData('label');
+ if (l) {
+ if (this.isSearch()) {
+ l += ' (' + this.sfolder + ')';
+ }
+ $('folderName').update(l);
+ }
+
+ if (this.folderswitch) {
+ this.folderswitch = false;
+
+ tmp = $('applyfilterlink');
+ if (tmp) {
+ if (this.isSearch() ||
+ (!DIMP.conf.filter_any &&
+ this.folder.toUpperCase() != 'INBOX')) {
+ tmp.hide();
+ } else {
+ tmp.show();
+ }
+ }
+
+ if (this.folder == DIMP.conf.spam_mbox) {
+ if (!DIMP.conf.spam_spammbox && $('button_spam')) {
+ [ $('button_spam').up(), $('ctx_message_spam') ].invoke('hide');
+ }
+ if ($('button_ham')) {
+ [ $('button_ham').up(), $('ctx_message_ham') ].invoke('show');
+ }
+ } else {
+ if ($('button_spam')) {
+ [ $('button_spam').up(), $('ctx_message_spam') ].invoke('show');
+ }
+ if ($('button_ham')) {
+ [ $('button_ham').up(), $('ctx_message_ham') ].invoke(DIMP.conf.ham_spammbox ? 'hide' : 'show');
+ }
+ }
+
+ /* Read-only changes. 'oa_setflag' is handled
+ * elsewhere. */
+ tmp = [ $('button_deleted') ].compact().invoke('up', 'SPAN');
+ [ 'ctx_message_', 'ctx_draft_' ].each(function(c) {
+ tmp = tmp.concat($(c + 'deleted', c + 'setflag', c + 'undeleted'));
+ });
+
+ if (this.viewport.getMetaData('readonly')) {
+ tmp.compact().invoke('hide');
+ $('folderName').next().show();
+ } else {
+ tmp.compact().invoke('show');
+ $('folderName').next().hide();
+ }
+ } else if (this.filtertoggle &&
+ this.viewport.getMetaData('sortby') == DIMP.conf.sortthread) {
+ ssc = DIMP.conf.sortdate;
+ }
+
+ this.setSortColumns(ssc);
+ }.bind(this),
+ onDeselect: this._deselect.bind(this),
+ onEndFetch: this.loadingImg.bind(this, 'viewport', false),
+ onFail: function() {
+ if ($('dimpmain_folder').visible()) {
+ DimpCore.showNotifications([ { type: 'horde.error', message: DIMP.text.listmsg_timeout } ]);
+ }
+ this.loadingImg('viewport', false);
+ }.bind(this),
+ onFetch: this.loadingImg.bind(this, 'viewport', true),
+ onSelect: this._select.bind(this),
+ onSlide: this.setMessageListTitle.bind(this),
+ onSplitBarChange: function() {
+ this._updatePrefs('dimp_splitbar', this.viewport.getPageSize());
+ }.bind(this),
+ onWait: function() {
+ if ($('dimpmain_folder').visible()) {
+ DimpCore.showNotifications([ { type: 'horde.warning', message: DIMP.text.listmsg_wait } ]);
+ }
+ }
+ });
+
+ // If starting in no preview mode, need to set the no preview class
+ if (!DIMP.conf.preview_pref) {
+ $('msgList').addClassName('msglistNoPreview');
+ }
+ },
+
+ _addMouseEvents: function(p, popdown)
+ {
+ if (popdown) {
+ popdown.insert({ after: new Element('SPAN', { className: 'iconImg popdownImg popdown', id: p.id + '_img' }) });
+ p.id += '_img';
+ p.offset = popdown.up();
+ p.left = true;
+ }
+
+ DimpCore.DMenu.addElement(p.id, 'ctx_' + p.type, p);
+ },
+
+ _removeMouseEvents: function(elt)
+ {
+ var d, id = $(elt).readAttribute('id');
+
+ if (id) {
+ if (d = DragDrop.Drags.getDrag(id)) {
+ d.destroy();
+ }
+
+ DimpCore.DMenu.removeElement(id);
+ }
+ },
+
+ contextOnClick: function(parentfunc, elt, baseelt, menu)
+ {
+ var flag, id = elt.readAttribute('id');
+
+ switch (id) {
+ case 'ctx_folder_create':
+ this.createSubFolder(baseelt);
+ break;
+
+ case 'ctx_container_rename':
+ case 'ctx_folder_rename':
+ this.renameFolder(baseelt);
+ break;
+
+ case 'ctx_folder_empty':
+ mbox = baseelt.up('LI').readAttribute('mbox');
+ if (window.confirm(DIMP.text.empty_folder.replace(/%s/, mbox))) {
+ DimpCore.doAction('EmptyFolder', { view: mbox }, null, this._emptyFolderCallback.bind(this));
+ }
+ break;
+
+ case 'ctx_folder_delete':
+ mbox = baseelt.up('LI').readAttribute('title');
+ if (window.confirm(DIMP.text.delete_folder.replace(/%s/, mbox))) {
+ DimpCore.doAction('DeleteFolder', { view: mbox }, null, this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this)));
+ }
+ break;
+
+ case 'ctx_folder_seen':
+ case 'ctx_folder_unseen':
+ this.flagAll('\\seen', id == 'ctx_folder_seen', baseelt.up('LI').readAttribute('mbox'));
+ break;
+
+ case 'ctx_folder_poll':
+ case 'ctx_folder_nopoll':
+ this.modifyPoll(baseelt.up('LI').readAttribute('mbox'), id == 'ctx_folder_poll');
+ break;
+
+ case 'ctx_folder_sub':
+ case 'ctx_folder_unsub':
+ this.subscribeFolder(baseelt.up('LI').readAttribute('mbox'), id == 'ctx_folder_sub');
+ break;
+
+ case 'ctx_container_create':
+ this.createSubFolder(baseelt);
+ break;
+
+ case 'ctx_folderopts_new':
+ this.createBaseFolder();
+ break;
+
+ case 'ctx_folderopts_sub':
+ case 'ctx_folderopts_unsub':
+ this.toggleSubscribed();
+ break;
+
+ case 'ctx_folderopts_expand':
+ case 'ctx_folderopts_collapse':
+ $('normalfolders').select('LI.folder').each(function(f) {
+ this._toggleSubFolder(f, id == 'ctx_folderopts_expand' ? 'exp' : 'col', true);
+ }.bind(this));
+ break;
+
+ case 'ctx_message_spam':
+ case 'ctx_message_ham':
+ this.reportSpam(id == 'ctx_message_spam');
+ break;
+
+ case 'ctx_message_blacklist':
+ case 'ctx_message_whitelist':
+ this.blacklist(id == 'ctx_message_blacklist');
+ break;
+
+ case 'ctx_draft_deleted':
+ case 'ctx_message_deleted':
+ this.deleteMsg();
+ break;
+
+ case 'ctx_message_forward':
+ this.composeMailbox('forward');
+ break;
+
+ case 'ctx_draft_resume':
+ this.composeMailbox('resume');
+ break;
+
+ case 'ctx_reply_reply':
+ case 'ctx_reply_reply_all':
+ case 'ctx_reply_reply_list':
+ this.composeMailbox(id.substring(10));
+ break;
+
+ case 'previewtoggle':
+ this.togglePreviewPane();
+ break;
+
+ case 'oa_blacklist':
+ case 'oa_whitelist':
+ this.blacklist(id == 'oa_blacklist');
+ break;
+
+ case 'ctx_draft_undeleted':
+ case 'ctx_message_undeleted':
+ case 'oa_undeleted':
+ this.flag('\\deleted', false);
+
+ case 'oa_selectall':
+ this.selectAll();
+ break;
+
+ case 'oa_purge_deleted':
+ this.purgeDeleted();
+ break;
+
+ case 'ctx_qsearchopts_basic':
+ alert('Placeholder for basic search');
+ break;
+
+ case 'ctx_qsearchopts_advanced':
+ alert('Placeholder for advanced search');
+ break;
+
+ case 'ctx_qsearchopts_all':
+ case 'ctx_qsearchopts_body':
+ case 'ctx_qsearchopts_from':
+ case 'ctx_qsearchopts_subject':
+ DIMP.conf.qsearchfield = id.substring(16);
+ this._updatePrefs('dimp_qsearch_field', DIMP.conf.qsearchfield);
+ break;
+
+ default:
+ if (menu.endsWith('_setflag') || menu.endsWith('_unsetflag')) {
+ flag = elt.readAttribute('flag');
+ this.flag(flag, this.convertFlag(flag, menu.endsWith('_setflag')));
+ } else {
+ parentfunc(elt, baseelt, menu);
+ }
+ break;
+ }
+ },
+
+ contextOnShow: function(parentfunc, ctx_id, baseelt)
+ {
+ var elts, ob, sel, tmp;
+
+ switch (ctx_id) {
+ case 'ctx_folder':
+ elts = $('ctx_folder_create', 'ctx_folder_rename', 'ctx_folder_delete');
+ baseelt = baseelt.up('LI');
+
+ if (baseelt.readAttribute('mbox') == 'INBOX') {
+ elts.invoke('hide');
+ if ($('ctx_folder_sub')) {
+ $('ctx_folder_sub', 'ctx_folder_unsub').invoke('hide');
+ }
+ } else {
+ if ($('ctx_folder_sub')) {
+ tmp = baseelt.hasClassName('unsubFolder');
+ [ $('ctx_folder_sub') ].invoke(tmp ? 'show' : 'hide');
+ [ $('ctx_folder_unsub') ].invoke(tmp ? 'hide' : 'show');
+ }
+
+ if (DIMP.conf.fixed_folders &&
+ DIMP.conf.fixed_folders.indexOf(baseelt.readAttribute('mbox')) != -1) {
+ elts.shift();
+ elts.invoke('hide');
+ } else {
+ elts.invoke('show');
+ }
+ }
+
+ tmp = baseelt.hasAttribute('u');
+ [ $('ctx_folder_poll') ].invoke(tmp ? 'hide' : 'show');
+ [ $('ctx_folder_nopoll') ].invoke(tmp ? 'show' : 'hide');
+ break;
+
+ case 'ctx_reply':
+ sel = this.viewport.getSelected();
+ if (sel.size() == 1) {
+ ob = sel.get('dataob').first();
+ }
+ [ $('ctx_reply_reply_list') ].invoke(ob && ob.listmsg ? 'show' : 'hide');
+ break;
+
+ case 'ctx_otheractions':
+ tmp = $('oa_blacklist', 'oa_whitelist', 'oa_undeleted');
+ if (this.viewport.getMetaData('readonly')) {
+ $('oa_setflag', 'oa_unsetflag').invoke('hide');
+ } else {
+ tmp = tmp.concat($('oa_setflag', 'oa_unsetflag'));
+ }
+ tmp.compact().invoke(this.viewport.getSelected().size() ? 'show' : 'hide');
+ break;
+
+ case 'ctx_qsearchopts':
+ $(ctx_id).descendants().invoke('removeClassName', 'contextSelected');
+ $(ctx_id + '_' + DIMP.conf.qsearchfield).addClassName('contextSelected');
+ break;
+
+ default:
+ parentfunc(ctx_id, baseelt);
+ break;
+ }
+ },
+
+ updateTitle: function()
+ {
+ var elt, unseen,
+ label = this.viewport.getMetaData('label');
+
+ if (this.isSearch()) {
+ label += ' (' + this.sfolder + ')';
+ } else {
+ elt = $(this.getFolderId(this.folder));
+ if (elt) {
+ unseen = elt.readAttribute('u');
+ if (unseen > 0) {
+ label += ' (' + unseen + ')';
+ }
+ }
+ }
+ DimpCore.setTitle(label);
+ },
+
+ sort: function(e)
+ {
+ // Don't change sort if we are past the sortlimit
+ if (this.viewport.getMetaData('sortlimit')) {
+ return;
+ }
+
+ var s, sortby,
+ elt = e.element();
+
+ if (!elt.hasAttribute('sortby')) {
+ elt = elt.up('[sortby]');
+ if (!elt) {
+ return;
+ }
+ }
+ sortby = Number(elt.readAttribute('sortby'));
+
+ if (sortby == this.viewport.getMetaData('sortby')) {
+ s = { sortdir: (this.viewport.getMetaData('sortdir') ? 0 : 1) };
+ this.viewport.setMetaData({ sortdir: s.sortdir });
+ } else {
+ s = { sortby: sortby };
+ this.viewport.setMetaData({ sortby: s.sortby });
+ }
+ this.setSortColumns(sortby);
+ this.viewport.reload(s);
+ },
+
+ setSortColumns: function(sortby)
+ {
+ var tmp,
+ m = $('msglistHeader');
+
+ if (Object.isUndefined(sortby)) {
+ sortby = this.viewport.getMetaData('sortby');
+ }
+
+ tmp = m.down('small[sortby=' + sortby + ']');
+ if (tmp && tmp.up().visible()) {
+ tmp.up(1).childElements().invoke('toggle');
+ }
+
+ tmp = m.down('div.msgFrom a');
+ if (this.viewport.getMetaData('special')) {
+ tmp.hide().next().show();
+ } else {
+ tmp.show().next().hide();
+ }
+
+ tmp = m.down('div.msgSubject a');
+ if (this.isSearch() ||
+ this.viewport.getMetaData('nothread') ||
+ this.viewport.getMetaData('sortlimit')) {
+ tmp.show().next().hide();
+ tmp.down().hide();
+ } else {
+ tmp.down().show();
+ }
+
+ m.childElements().invoke('removeClassName', 'sortup').invoke('removeClassName', 'sortdown');
+
+ tmp = m.down('div a[sortby=' + sortby + ']');
+ if (tmp) {
+ tmp.up().addClassName(this.viewport.getMetaData('sortdir') ? 'sortup' : 'sortdown');
+ }
+ },
+
+ // Preview pane functions
+ togglePreviewPane: function()
+ {
+ var p = DIMP.conf.preview_pref = !DIMP.conf.preview_pref;
+ $('previewtoggle').setText(p ? DIMP.text.hide_preview : DIMP.text.show_preview);
+ [ $('msgList') ].invoke(p ? 'removeClassName' : 'addClassName', 'msglistNoPreview');
+ this._updatePrefs('show_preview', Number(p));
+ this.viewport.showSplitPane(p);
+ if (p) {
+ this.initPreviewPane();
+ }
+ },
+
+ loadPreview: function(data, params)
+ {
+ var pp_uid;
+
+ if (!$('previewPane').visible()) {
+ return;
+ }
+
+ if (!params) {
+ if (this.pp &&
+ this.pp.imapuid == data.imapuid &&
+ this.pp.view == data.view) {
+ return;
+ }
+ this.pp = data;
+ pp_uid = this._getPPId(data.imapuid, data.view);
+
+ if (this.ppfifo.indexOf(pp_uid) != -1) {
+ // There is a chance that the message may have been marked
+ // as unseen since first being viewed. If so, we need to
+ // explicitly flag as seen here.
+ if (!this.hasFlag('\\seen', data)) {
+ this.flag('\\seen', true);
+ }
+ return this._loadPreviewCallback(this.ppcache[pp_uid]);
+ }
+ }
+
+ this.loadingImg('msg', true);
+
+ DimpCore.doAction('ShowPreview', params || {}, this.viewport.createSelection('dataob', this.pp), this.bcache.get('loadPC') || this.bcache.set('loadPC', this._loadPreviewCallback.bind(this)));
+ },
+
+ _loadPreviewCallback: function(resp)
+ {
+ var ppuid, row, search, tmp,
+ pm = $('previewMsg'),
+ r = resp.response,
+ t = $('msgHeadersContent').down('THEAD');
+
+ if (!r.error) {
+ search = this.viewport.getSelection().search({ imapuid: { equal: [ r.index ] }, view: { equal: [ r.mailbox ] } });
+ if (search.size()) {
+ row = search.get('dataob').first();
+ this.updateSeenUID(row, 1);
+ }
+ }
+
+ if (this.pp &&
+ (this.pp.imapuid != r.index ||
+ this.pp.view != r.mailbox)) {
+ return;
+ }
+
+ if (r.error || this.viewport.getSelected().size() != 1) {
+ if (r.error) {
+ DimpCore.showNotifications([ { type: r.errortype, message: r.error } ]);
+ }
+ this.clearPreviewPane();
+ return;
+ }
+
+ // Store in cache.
+ ppuid = this._getPPId(r.index, r.mailbox);
+ this._expirePPCache([ ppuid ]);
+ this.ppcache[ppuid] = resp;
+ this.ppfifo.push(ppuid);
+
+ DimpCore.removeAddressLinks(pm);
+
+ // Add subject
+ tmp = pm.select('.subject');
+ tmp.invoke('update', r.subject === null ? '[' + DIMP.text.badsubject + ']' : r.subject);
+
+ // Add date
+ $('msgHeadersColl').select('.date').invoke('update', r.minidate);
+ $('msgHeaderDate').select('.date').invoke('update', r.localdate);
+
+ // Add from/to/cc headers
+ [ 'from', 'to', 'cc' ].each(function(a) {
+ if (r[a]) {
+ (a == 'from' ? pm.select('.' + a) : [ t.down('.' + a) ]).each(function(elt) {
+ elt.replace(DimpCore.buildAddressLinks(r[a], elt.cloneNode(false)));
+ });
+ }
+ [ $('msgHeader' + a.capitalize()) ].invoke(r[a] ? 'show' : 'hide');
+ });
+
+ // Add attachment information
+ if (r.atc_label) {
+ $('msgAtc').show();
+ tmp = $('partlist');
+ tmp.hide().previous().update(new Element('SPAN', { className: 'atcLabel' }).insert(r.atc_label)).insert(r.atc_download);
+ if (r.atc_list) {
+ $('partlist_col').show();
+ $('partlist_exp').hide();
+ tmp.down('TABLE').update(r.atc_list);
+ }
+ } else {
+ $('msgAtc').hide();
+ }
+
+ // Add message information
+ if (r.log) {
+ this.updateMsgLog(r.log);
+ } else {
+ $('msgLogInfo').hide();
+ }
+
+ $('msgBody').update(r.msgtext);
+ this.loadingImg('msg', false);
+ $('previewInfo').hide();
+ $('previewPane').scrollTop = 0;
+ pm.show();
+
+ if (r.js) {
+ eval(r.js.join(';'));
+ }
+
+ this._addHistory('msg:' + row.view + ':' + row.imapuid);
+ },
+
+ // opts = index, mailbox
+ updateMsgLog: function(log, opts)
+ {
+ var tmp;
+
+ if (!opts ||
+ (this.pp.imapuid == opts.index &&
+ this.pp.view == opts.mailbox)) {
+ $('msgLogInfo').show();
+
+ if (opts) {
+ $('msgloglist_col').show();
+ $('msgloglist_exp').hide();
+ }
+
+ DimpCore.updateMsgLog(log);
+ }
+
+ if (opts) {
+ tmp = this._getPPId(opts.index, opts.mailbox);
+ if (this.ppcache[tmp]) {
+ this.ppcache[tmp].response.log = log;
+ }
+ }
+ },
+
+ initPreviewPane: function()
+ {
+ var sel = this.viewport.getSelected();
+ if (sel.size() != 1) {
+ this.clearPreviewPane();
+ } else {
+ this.loadPreview(sel.get('dataob').first());
+ }
+ },
+
+ clearPreviewPane: function()
+ {
+ this.loadingImg('msg', false);
+ $('previewMsg').hide();
+ $('previewPane').scrollTop = 0;
+ $('previewInfo').show();
+ this.pp = null;
+ },
+
+ _toggleHeaders: function(elt, update)
+ {
+ if (update) {
+ DIMP.conf.toggle_pref = !DIMP.conf.toggle_pref;
+ this._updatePrefs('dimp_toggle_headers', Number(elt.id == 'th_expand'));
+ }
+ [ elt.up().select('A'), $('msgHeadersColl', 'msgHeaders') ].flatten().invoke('toggle');
+ },
+
+ _expirePPCache: function(ids)
+ {
+ this.ppfifo = this.ppfifo.diff(ids);
+ ids.each(function(i) {
+ delete this.ppcache[i];
+ }, this);
+
+ if (this.ppfifo.size() > this.ppcachesize) {
+ delete this.ppcache[this.ppfifo.shift()];
+ }
+ },
+
+ _getPPId: function(index, mailbox)
+ {
+ return index + '|' + mailbox;
+ },
+
+ // Labeling functions
+ updateSeenUID: function(r, setflag)
+ {
+ var isunseen = !this.hasFlag('\\seen', r),
+ sel, unseen;
+
+ if ((setflag && !isunseen) || (!setflag && isunseen)) {
+ return false;
+ }
+
+ sel = this.viewport.createSelection('dataob', r);
+ unseen = Number($(this.getFolderId(r.view)).readAttribute('u'));
+
+ unseen += setflag ? -1 : 1;
+ this.updateFlag(sel, '\\seen', setflag);
+
+ this.updateUnseenStatus(r.view, unseen);
+ },
+
+ updateUnseenStatus: function(mbox, unseen)
+ {
+ if (this.viewport) {
+ this.viewport.setMetaData({ unseen: unseen }, mbox);
+ }
+
+ this.setFolderLabel(mbox, unseen);
+
+ if (this.folder == mbox) {
+ this.updateTitle();
+ }
+ },
+
+ setMessageListTitle: function()
+ {
+ var offset,
+ rows = this.viewport.getMetaData('total_rows');
+
+ if (rows > 0) {
+ offset = this.viewport.currentOffset();
+ $('msgHeader').update(DIMP.text.messages + ' ' + (offset + 1) + ' - ' + (Math.min(offset + this.viewport.getPageSize(), rows)) + ' ' + DIMP.text.of + ' ' + rows);
+ } else {
+ $('msgHeader').update(DIMP.text.nomessages);
+ }
+ },
+
+ setFolderLabel: function(f, unseen)
+ {
+ var fid = this.getFolderId(f),
+ elt = $(fid);
+
+ if (!elt ||
+ !elt.hasAttribute('u') ||
+ elt.readAttribute('u') == unseen) {
+ return;
+ }
+
+ unseen = Number(unseen);
+ elt.writeAttribute('u', unseen);
+
+ if (f == 'INBOX' && window.fluid) {
+ window.fluid.setDockBadge(unseen ? unseen : '');
+ }
+
+ $(fid).down('A').update((unseen > 0) ?
+ new Element('STRONG').insert(elt.readAttribute('l')).insert(' ').insert(new Element('SPAN', { className: 'count', dir: 'ltr' }).insert('(' + unseen + ')')) :
+ elt.readAttribute('l'));
+ },
+
+ getFolderId: function(f)
+ {
+ return 'fld' + f.replace(/_/g,'__').replace(/\W/g, '_');
+ },
+
+ getSubFolderId: function(f)
+ {
+ return 'sub' + f;
+ },
+
+ /* Folder list updates. */
+ poll: function()
+ {
+ var args = {};
+
+ // Reset poll folder counter.
+ this.setPoll();
+
+ // Check for label info - it is possible that the mailbox may be
+ // loading but not complete yet and sending this request will cause
+ // duplicate info to be returned.
+ if (this.folder &&
+ $('dimpmain_folder').visible() &&
+ this.viewport.getMetaData('label')) {
+ args = this.viewport.addRequestParams({});
+ }
+ $('checkmaillink').down('A').update('[' + DIMP.text.check + ']');
+ DimpCore.doAction('Poll', args, null, this.bcache.get('pollFC') || this.bcache.set('pollFC', this._pollCallback.bind(this)));
+ },
+
+ _pollCallback: function(r)
+ {
+ r = r.response;
+ if (r.poll) {
+ $H(r.poll).each(function(u) {
+ this.updateUnseenStatus(u.key, u.value);
+ }, this);
+ }
+ if (r.quota) {
+ this._displayQuota(r.quota);
+ }
+ $('checkmaillink').down('A').update(DIMP.text.getmail);
+ },
+
+ _displayQuota: function(r)
+ {
+ var q = $('quota').cleanWhitespace();
+ q.setText(r.m);
+ q.down('SPAN.used IMG').writeAttribute({ width: 99 - r.p });
+ },
+
+ setPoll: function()
+ {
+ if (DIMP.conf.refresh_time) {
+ if (this.pollPE) {
+ this.pollPE.stop();
+ }
+ // Don't cache - this code is only run once.
+ this.pollPE = new PeriodicalExecuter(this.poll.bind(this), DIMP.conf.refresh_time);
+ }
+ },
+
+ _portalCallback: function(r)
+ {
+ if (r.response.linkTags) {
+ var head = $(document.documentElement).down('HEAD');
+ r.response.linkTags.each(function(newLink) {
+ var link = new Element('LINK', { type: 'text/css', rel: 'stylesheet', href: newLink.href });
+ if (newLink.media) {
+ link.media = newLink.media;
+ }
+ head.insert(link);
+ });
+ }
+ $('dimpmain_portal').update(r.response.portal);
+ },
+
+ /* Search functions. */
+ isSearch: function(id)
+ {
+ return (id ? id : this.folder) == DIMP.conf.qsearchid;
+ },
+
+ _quicksearchOnBlur: function()
+ {
+ $('qsearch').removeClassName('qsearchFocus');
+ if (!$F('qsearch_input')) {
+ this._setFilterText(true);
+ }
+ },
+
+ quicksearchRun: function()
+ {
+ if (this.isSearch()) {
+ this.viewport.reload();
+ } else {
+ this.sfolder = this.folder;
+ $('qsearch_close').show();
+ this.loadMailbox(DIMP.conf.qsearchid);
+ }
+ },
+
+ // 'noload' = (boolean) If true, don't load the mailbox
+ quicksearchClear: function(noload)
+ {
+ if (this.isSearch()) {
+ $('qsearch_close').hide();
+ if (!$('qsearch').hasClassName('qsearchFocus')) {
+ this._setFilterText(true);
+ }
+ this.resetSelected();
+ if (!noload) {
+ this.loadMailbox(this.sfolder);
+ }
+ this.viewport.deleteView(DIMP.conf.qsearchid);
+ }
+ },
+
+ // d = (boolean) Deactivate filter input?
+ _setFilterText: function(d)
+ {
+ $('qsearch_input').setValue(d ? DIMP.text.search : '');
+ [ $('qsearch') ].invoke(d ? 'removeClassName' : 'addClassName', 'qsearchActive');
+ },
+
+ /* Enable/Disable DIMP action buttons as needed. */
+ toggleButtons: function()
+ {
+ var disable = (this.selectedCount() == 0);
+ $('dimpmain_folder_top').select('DIV.dimpActions A.noselectDisable').each(function(b) {
+ [ b.up() ].invoke(disable ? 'addClassName' : 'removeClassName', 'disabled');
+ DimpCore.DMenu.disable(b.readAttribute('id') + '_img', true, disable);
+ });
+ },
+
+ /* Drag/Drop handler. */
+ _folderDropHandler: function(drop, drag, e)
+ {
+ var dropbase, sel, uids,
+ foldername = drop.readAttribute('mbox'),
+ ftype = drop.readAttribute('ftype');
+
+ if (drag.hasClassName('folder')) {
+ dropbase = (drop == $('dropbase'));
+ if (dropbase ||
+ (ftype != 'special' && !this.isSubfolder(drag, drop))) {
+ DimpCore.doAction('RenameFolder', { old_name: drag.readAttribute('mbox'), new_parent: dropbase ? '' : foldername, new_name: drag.readAttribute('l') }, null, this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this)));
+ }
+ } else if (ftype != 'container') {
+ sel = this.viewport.getSelected();
+
+ if (sel.size()) {
+ // Dragging multiple selected messages.
+ uids = sel;
+ } else if (drag.readAttribute('mbox') != foldername) {
+ // Dragging a single unselected message.
+ uids = this.viewport.createSelection('domid', drag.id);
+ }
+
+ if (uids.size()) {
+ if (e.ctrlKey) {
+ DimpCore.doAction('CopyMessage', this.viewport.addRequestParams({ tofld: foldername }), uids, this.bcache.get('pollFC') || this.bcache.set('pollFC', this._pollCallback.bind(this)));
+ } else if (this.folder != foldername) {
+ // Don't allow drag/drop to the current folder.
+ this.updateFlag(uids, '\\deleted', true);
+ DimpCore.doAction('MoveMessage', this.viewport.addRequestParams({ tofld: foldername }), uids, this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)));
+ }
+ }
+ }
+ },
+
+ dragCaption: function()
+ {
+ var cnt = this.selectedCount();
+ return cnt + ' ' + (cnt == 1 ? DIMP.text.message : DIMP.text.messages);
+ },
+
+ /* Keydown event handler */
+ keydownHandler: function(e)
+ {
+ var co, form, h, pp, ps, r, row, rowoff, sel,
+ elt = e.element(),
+ kc = e.keyCode || e.charCode;
+
+ // Only catch keyboard shortcuts in message list view.
+ if (!$('dimpmain_folder').visible()) {
+ return;
+ }
+
+ // Form catching - normally we will ignore, but certain cases we want
+ // to catch.
+ form = e.findElement('FORM');
+ if (form) {
+ switch (kc) {
+ case Event.KEY_ESC:
+ case Event.KEY_TAB:
+ // Catch escapes in search box
+ if (elt.readAttribute('id') == 'qsearch_input') {
+ if (kc == Event.KEY_ESC || !elt.getValue()) {
+ this.quicksearchClear();
+ }
+ elt.blur();
+ e.stop();
+ }
+ break;
+
+ case Event.KEY_RETURN:
+ // Catch returns in RedBox
+ if (form.readAttribute('id') == 'RB_folder') {
+ this.cfolderaction(e);
+ e.stop();
+ } else if (elt.readAttribute('id') == 'qsearch_input') {
+ if ($F('qsearch_input')) {
+ this.quicksearchRun();
+ } else {
+ this.quicksearchClear();
+ }
+ e.stop();
+ }
+ break;
+ }
+
+ return;
+ }
+
+ sel = this.viewport.getSelected();
+
+ switch (kc) {
+ case Event.KEY_DELETE:
+ case Event.KEY_BACKSPACE:
+ r = sel.get('dataob');
+ if (e.shiftKey) {
+ this.moveSelected((r.last().rownum == this.viewport.getMetaData('total_rows')) ? (r.first().rownum - 1) : (r.last().rownum + 1), true);
+ }
+ this.deleteMsg({ vs: sel });
+ e.stop();
+ break;
+
+ case Event.KEY_UP:
+ case Event.KEY_DOWN:
+ if (e.shiftKey && this.lastrow != -1) {
+ row = this.viewport.createSelection('rownum', this.lastrow + ((kc == Event.KEY_UP) ? -1 : 1));
+ if (row.size()) {
+ row = row.get('dataob').first();
+ this.viewport.scrollTo(row.rownum);
+ this.msgSelect(row.domid, { shift: true });
+ }
+ } else {
+ this.moveSelected(kc == Event.KEY_UP ? -1 : 1);
+ }
+ e.stop();
+ break;
+
+ case Event.KEY_PAGEUP:
+ case Event.KEY_PAGEDOWN:
+ if (e.altKey) {
+ pp = $('previewPane');
+ h = pp.getHeight();
+ if (h != pp.scrollHeight) {
+ switch (kc) {
+ case Event.KEY_PAGEUP:
+ pp.scrollTop = Math.max(pp.scrollTop - h, 0);
+ break;
+
+ case Event.KEY_PAGEDOWN:
+ pp.scrollTop = Math.min(pp.scrollTop + h, pp.scrollHeight - h + 1);
+ break;
+ }
+ }
+ e.stop();
+ } else if (!e.ctrlKey && !e.shiftKey && !e.metaKey) {
+ ps = this.viewport.getPageSize() - 1;
+ move = ps * (kc == Event.KEY_PAGEUP ? -1 : 1);
+ if (sel.size() == 1) {
+ co = this.viewport.currentOffset();
+ rowoff = sel.get('rownum').first() - 1;
+ switch (kc) {
+ case Event.KEY_PAGEUP:
+ if (co != rowoff) {
+ move = co - rowoff;
+ }
+ break;
+
+ case Event.KEY_PAGEDOWN:
+ if ((co + ps) != rowoff) {
+ move = co + ps - rowoff;
+ }
+ break;
+ }
+ }
+ this.moveSelected(move);
+ e.stop();
+ }
+ break;
+
+ case Event.KEY_HOME:
+ case Event.KEY_END:
+ this.moveSelected(kc == Event.KEY_HOME ? 1 : this.viewport.getMetaData('total_rows'), true);
+ e.stop();
+ break;
+
+ case Event.KEY_RETURN:
+ if (!elt.match('input')) {
+ // Popup message window if single message is selected.
+ if (sel.size() == 1) {
+ this.msgWindow(sel.get('dataob').first());
+ }
+ }
+ e.stop();
+ break;
+
+ case 65: // A
+ case 97: // a
+ if (e.ctrlKey) {
+ this.selectAll();
+ e.stop();
+ }
+ break;
+ }
+ },
+
+ dblclickHandler: function(e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = e.element(),
+ tmp;
+
+ if (!elt.hasClassName('vpRow')) {
+ elt = elt.up('.vpRow');
+ }
+
+ if (elt) {
+ tmp = this.viewport.createSelection('domid', elt.identify()).get('dataob').first();
+ tmp.draft
+ ? DimpCore.compose('resume', { folder: tmp.view, uid: tmp.imapuid })
+ : this.msgWindow(tmp);
+ }
+
+ e.stop();
+ },
+
+ clickHandler: function(parentfunc, e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = e.element(),
+ id, tmp;
+
+ while (Object.isElement(elt)) {
+ id = elt.readAttribute('id');
+
+ switch (id) {
+ case 'normalfolders':
+ case 'specialfolders':
+ this._handleFolderMouseClick(e);
+ break;
+
+ case 'hometab':
+ case 'logolink':
+ this.go('portal');
+ e.stop();
+ return;
+
+ case 'button_compose':
+ case 'composelink':
+ DimpCore.compose('new');
+ e.stop();
+ return;
+
+ case 'checkmaillink':
+ this.poll();
+ e.stop();
+ return;
+
+ case 'fetchmaillink':
+ IMPDialog.display({ dialog_load: DIMP.conf.URI_AJAX + '/FetchmailDialog' });
+ e.stop();
+ return;
+
+ case 'applyfilterlink':
+ if (this.viewport) {
+ this.viewport.reload({ applyfilter: 1 });
+ }
+ e.stop();
+ return;
+
+ case 'appportal':
+ case 'appoptions':
+ this.go(id.substring(3));
+ e.stop();
+ return;
+
+ case 'applogout':
+ elt.down('A').update('[' + DIMP.text.onlogout + ']');
+ DimpCore.logout();
+ e.stop();
+ return;
+
+ case 'folderopts':
+ DimpCore.DMenu.trigger($('folderopts_img'), true);
+ return;
+
+ case 'button_forward':
+ case 'button_reply':
+ this.composeMailbox(id == 'button_reply' ? 'reply' : 'forward');
+ break;
+
+ case 'button_ham':
+ case 'button_spam':
+ this.reportSpam(id == 'button_spam');
+ e.stop();
+ return;
+
+ case 'button_deleted':
+ this.deleteMsg();
+ e.stop();
+ return;
+
+ case 'button_other':
+ DimpCore.DMenu.trigger(e.findElement('A').next(), true);
+ e.stop();
+ return;
+
+ case 'msglistHeader':
+ this.sort(e);
+ e.stop();
+ return;
+
+ case 'th_expand':
+ case 'th_collapse':
+ this._toggleHeaders(elt, true);
+ break;
+
+ case 'msgloglist_toggle':
+ case 'partlist_toggle':
+ tmp = (id == 'partlist_toggle') ? 'partlist' : 'msgloglist';
+ $(tmp + '_col', tmp + '_exp').invoke('toggle');
+ Effect.toggle(tmp, 'blind', {
+ duration: 0.2,
+ queue: {
+ position: 'end',
+ scope: tmp,
+ limit: 2
+ }
+ });
+ break;
+
+ case 'msg_newwin':
+ case 'msg_newwin_options':
+ this.msgWindow(this.viewport.getSelection().search({ imapuid: { equal: [ this.pp.imapuid ] } , view: { equal: [ this.pp.view ] } }).get('dataob').first());
+ e.stop();
+ return;
+
+ case 'msg_view_source':
+ DimpCore.popupWindow(DimpCore.addURLParam(DIMP.conf.URI_VIEW, { uid: this.pp.imapuid, mailbox: this.pp.view, actionID: 'view_source', id: 0 }, true), DIMP.conf.msg_index + '|' + DIMP.conf.msg_folder);
+ break;
+
+ case 'applicationfolders':
+ tmp = e.element();
+ if (!tmp.hasClassName('custom')) {
+ tmp = tmp.up('LI.custom');
+ }
+ if (tmp) {
+ this.go('app:' + tmp.down('A').identify().substring(3));
+ e.stop();
+ return;
+ }
+ break;
+
+ case 'tabbar':
+ if (e.element().hasClassName('applicationtab')) {
+ this.go('app:' + e.element().identify().substring(6));
+ e.stop();
+ return;
+ }
+ break;
+
+ case 'dimpmain_portal':
+ if (e.element().match('H1.header a')) {
+ this.go('app:' + e.element().readAttribute('app'));
+ e.stop();
+ return;
+ }
+ break;
+
+ case 'qsearch_icon':
+ DimpCore.DMenu.trigger($('qsearch_icon'), true);
+ e.stop();
+ return;
+
+ case 'qsearch':
+ elt.addClassName('qsearchFocus');
+ if (!elt.hasClassName('qsearchActive')) {
+ this._setFilterText(false);
+ }
+ $('qsearch_input').focus();
+ break;
+
+ case 'qsearch_close':
+ this.quicksearchClear();
+ e.stop();
+ return;
+
+ default:
+ if (elt.hasClassName('RBFolderOk')) {
+ this.cfolderaction(e);
+ e.stop();
+ return;
+ } else if (elt.hasClassName('RBFolderCancel')) {
+ this._closeRedBox();
+ e.stop();
+ return;
+ }
+ }
+
+ elt = elt.up();
+ }
+
+ parentfunc(e);
+ },
+
+ mouseoverHandler: function(e)
+ {
+ if (DragDrop.Drags.drag) {
+ var elt = e.element();
+ if (elt.hasClassName('exp')) {
+ this._toggleSubFolder(elt.up(), 'exp');
+ }
+ }
+ },
+
+ /* Handle rename folder actions. */
+ renameFolder: function(folder)
+ {
+ if (Object.isUndefined(folder)) {
+ return;
+ }
+
+ folder = $(folder);
+ var n = this._createFolderForm(this._folderAction.bindAsEventListener(this, folder, 'rename'), DIMP.text.rename_prompt);
+ n.down('input').setValue(folder.readAttribute('l'));
+ },
+
+ /* Handle insert folder actions. */
+ createBaseFolder: function()
+ {
+ this._createFolderForm(this._folderAction.bindAsEventListener(this, '', 'create'), DIMP.text.create_prompt);
+ },
+
+ createSubFolder: function(folder)
+ {
+ if (!Object.isUndefined(folder)) {
+ this._createFolderForm(this._folderAction.bindAsEventListener(this, $(folder), 'createsub'), DIMP.text.createsub_prompt);
+ }
+ },
+
+ _createFolderForm: function(action, text)
+ {
+ var n = $($('folderform').down().cloneNode(true)).writeAttribute('id', 'RB_folder');
+ n.down('P').insert(text);
+
+ this.cfolderaction = action;
+
+ RedBox.overlay = true;
+ RedBox.onDisplay = Form.focusFirstElement.curry(n);
+ RedBox.showHtml(n);
+ return n;
+ },
+
+ _closeRedBox: function()
+ {
+ RedBox.close();
+ this.cfolderaction = null;
+ },
+
+ _folderAction: function(e, folder, mode)
+ {
+ this._closeRedBox();
+
+ var action, params, val,
+ form = e.findElement('form');
+ val = $F(form.down('input'));
+
+ if (val) {
+ switch (mode) {
+ case 'rename':
+ folder = folder.up('LI');
+ if (folder.readAttribute('l') != val) {
+ action = 'RenameFolder';
+ params = { old_name: folder.readAttribute('mbox'),
+ new_parent: folder.up().hasClassName('folderlist') ? '' : folder.up(1).previous().readAttribute('mbox'),
+ new_name: val };
+ }
+ break;
+
+ case 'create':
+ case 'createsub':
+ action = 'CreateFolder';
+ params = { view: val };
+ if (mode == 'createsub') {
+ params.parent = folder.up('LI').readAttribute('mbox');
+ }
+ break;
+ }
+
+ if (action) {
+ DimpCore.doAction(action, params, null, this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this)));
+ }
+ }
+ },
+
+ /* Folder action callback functions. */
+ _folderCallback: function(r)
+ {
+ r = r.response;
+ if (r.d) {
+ r.d.each(this.bcache.get('deleteFolder') || this.bcache.set('deleteFolder', this.deleteFolder.bind(this)));
+ }
+ if (r.c) {
+ r.c.each(this.bcache.get('changeFolder') || this.bcache.set('changeFolder', this.changeFolder.bind(this)));
+ }
+ if (r.a) {
+ r.a.each(this.bcache.get('createFolder') || this.bcache.set('createFolder', this.createFolder.bind(this)));
+ }
+ },
+
+ _deleteCallback: function(r)
+ {
+ var search = null, uids = [], vs;
+
+ this.loadingImg('viewport', false);
+ this._pollCallback(r);
+
+ r = r.response;
+ if (!r.uids || r.folder != this.folder) {
+ return;
+ }
+ r.uids = DimpCore.parseRangeString(r.uids);
+
+ // Need to convert uid list to listing of unique viewport IDs since
+ // we may be dealing with multiple mailboxes (i.e. virtual folders)
+ vs = this.viewport.getSelection(this.folder);
+ if (vs.getBuffer().getMetaData('search')) {
+ $H(r.uids).each(function(pair) {
+ pair.value.each(function(v) {
+ uids.push(v + pair.key);
+ });
+ });
+
+ search = this.viewport.getSelection().search({ vp_id: { equal: uids } });
+ } else {
+ r.uids = r.uids[this.folder];
+ r.uids.each(function(f, u) {
+ uids.push(u + f);
+ }.curry(this.folder));
+ search = this.viewport.createSelection('uid', r.uids);
+ }
+
+ if (search.size()) {
+ if (r.remove) {
+ // TODO: Don't use cacheid
+ this.viewport.remove(search, { cacheid: r.cacheid, noupdate: r.ViewPort });
+ this._expirePPCache(uids);
+ } else {
+ // Need this to catch spam deletions.
+ this.updateFlag(search, '\\deleted', true);
+ }
+ }
+ },
+
+ _emptyFolderCallback: function(r)
+ {
+ if (r.response.mbox) {
+ if (this.folder == r.response.mbox) {
+ this.viewport.reload();
+ this.clearPreviewPane();
+ }
+ this.setFolderLabel(r.response.mbox, 0);
+ }
+ },
+
+ _flagAllCallback: function(r)
+ {
+ if (r.response) {
+ if (r.response.mbox == this.folder) {
+ r.response.flags.each(function(f) {
+ this.updateFlag(this.viewport.createSelection('rownum', $A($R(1, this.viewport.getMetaData('total_rows')))), f, r.response.set);
+ }, this);
+ }
+ this._pollCallback(r);
+ }
+ },
+
+ _folderLoadCallback: function(r)
+ {
+ this._folderCallback(r);
+
+ var nf = $('normalfolders'),
+ nfheight = nf.getStyle('max-height');
+
+ if (this.folder) {
+ this.highlightSidebar(this.getFolderId(this.folder));
+ }
+
+ $('foldersLoading').hide();
+ $('foldersSidebar').show();
+
+ // Fix for IE6 - which doesn't support max-height. We need to search
+ // for height: 0px instead (comment in IE 6 CSS explains this is
+ // needed for auto sizing).
+ if (nfheight !== null ||
+ (Prototype.Browser.IE &&
+ Object.isUndefined(nfheight) &&
+ (nf.getStyle('height') == '0px'))) {
+ this._sizeFolderlist();
+ Event.observe(window, 'resize', this._sizeFolderlist.bind(this));
+ }
+
+ if (r.response.quota) {
+ this._displayQuota(r.response.quota);
+ }
+ },
+
+ _handleFolderMouseClick: function(e)
+ {
+ var elt = e.element(),
+ li = elt.up('.folder') || elt.up('.custom');
+
+ if (!li) {
+ return;
+ }
+
+ if (elt.hasClassName('exp') || elt.hasClassName('col')) {
+ this._toggleSubFolder(li, 'tog');
+ } else {
+ switch (li.readAttribute('ftype')) {
+ case 'container':
+ case 'vcontainer':
+ e.stop();
+ break;
+
+ case 'folder':
+ case 'special':
+ case 'virtual':
+ e.stop();
+ return this.go('folder:' + li.readAttribute('mbox'));
+ }
+ }
+ },
+
+ _toggleSubFolder: function(base, mode, noeffect)
+ {
+ // Make sure all subfolders are expanded.
+ // The last 2 elements of ancestors() are the BODY and HTML tags -
+ // don't need to parse through them.
+ var subs = (mode == 'exp')
+ ? base.ancestors().slice(0, -2).reverse().findAll(function(n) { return n.hasClassName('subfolders'); })
+ : [ base.next('.subfolders') ];
+
+ subs.compact().each(function(s) {
+ if (mode == 'tog' ||
+ (mode == 'exp' && !s.visible()) ||
+ (mode == 'col' && s.visible())) {
+ s.previous().down().toggleClassName('exp').toggleClassName('col');
+
+ if (noeffect) {
+ s.toggle();
+ } else {
+ Effect.toggle(s, 'blind', {
+ duration: 0.2,
+ queue: {
+ position: 'end',
+ scope: 'subfolder'
+ }
+ });
+ }
+ }
+ }.bind(this));
+ },
+
+ // Folder actions.
+ // For format of the ob object, see DIMP::_createFolderElt().
+ createFolder: function(ob)
+ {
+ var div, f_node, ftype, li, ll, parent_e, tmp,
+ cname = 'folder',
+ fid = this.getFolderId(ob.m),
+ label = ob.l || ob.m,
+ mbox = ob.m,
+ submboxid = this.getSubFolderId(fid),
+ submbox = $(submboxid),
+ title = ob.t || ob.m;
+
+ if (ob.v) {
+ ftype = ob.co ? 'vcontainer' : 'virtual';
+ title = label;
+ } else if (ob.co) {
+ ftype = 'container';
+
+ /* This is a dummy container element to display child elements of
+ * a mailbox displayed in the 'specialfolders' section. */
+ if (ob.s) {
+ fid += '_special';
+ ob.s = false;
+ cname += ' specialContainer';
+ }
+ } else {
+ ftype = ob.s ? 'special' : 'folder';
+ }
+
+ if (ob.un) {
+ cname += ' unsubFolder';
+ }
+
+ div = new Element('DIV', { className: 'iconDiv' });
+ if (ob.i) {
+ div.setStyle({ backgroundImage: 'url("' + ob.i + '")' });
+ }
+
+ li = new Element('LI', { className: cname, id: fid, l: label, mbox: mbox, title: title }).insert(div).insert(new Element('A').insert(label));
+
+ // Now walk through the parent <ul> to find the right place to
+ // insert the new folder.
+ if (submbox) {
+ if (submbox.insert({ before: li }).visible()) {
+ // If an expanded parent mailbox was deleted, we need to toggle
+ // the icon accordingly.
+ div.addClassName('col');
+ }
+ } else {
+ div.addClassName(ob.ch ? 'exp' : (ob.cl || 'base'));
+
+ if (ob.s) {
+ parent_e = $('specialfolders');
+
+ /* Create a dummy container element in 'normalfolders'
+ * section. */
+ if (ob.ch) {
+ div.removeClassName('exp').addClassName(ob.cl || 'base');
+
+ tmp = Object.clone(ob);
+ tmp.co = true;
+ this.createFolder(tmp);
+ }
+ } else {
+ parent_e = ob.pa
+ ? $(this.getSubFolderId(this.getFolderId(ob.pa))).down()
+ : $('normalfolders');
+ }
+
+ /* Virtual folders are sorted on the server. */
+ if (!ob.v) {
+ ll = mbox.toLowerCase();
+ f_node = parent_e.childElements().find(function(node) {
+ var nodembox = node.readAttribute('mbox');
+ return nodembox &&
+ (!ob.s || nodembox != 'INBOX') &&
+ (ll < nodembox.toLowerCase());
+ });
+ }
+
+ if (f_node) {
+ f_node.insert({ before: li });
+ } else {
+ parent_e.insert(li);
+ }
+
+ // Make sure the sub<mbox> ul is created if necessary.
+ if (!ob.s && ob.ch) {
+ li.insert({ after: new Element('LI', { className: 'subfolders', id: submboxid }).insert(new Element('UL')).hide() });
+ }
+ }
+
+ li.writeAttribute('ftype', ftype);
+
+ // Make the new folder a drop target.
+ if (!ob.v) {
+ new Drop(li, this._folderDropConfig);
+ }
+
+ // Check for unseen messages
+ if (ob.po) {
+ li.writeAttribute('u', '');
+ this.setFolderLabel(mbox, ob.u);
+ }
+
+ switch (ftype) {
+ case 'special':
+ // For purposes of the contextmenu, treat special folders
+ // like regular folders.
+ ftype = 'folder';
+ // Fall through.
+
+ case 'container':
+ case 'folder':
+ new Drag(li, this._folderDragConfig);
+ this._addMouseEvents({ id: fid, type: ftype });
+ break;
+ }
+ },
+
+ deleteFolder: function(folder)
+ {
+ if (this.folder == folder) {
+ this.go('folder:INBOX');
+ }
+ this.deleteFolderElt(this.getFolderId(folder), true);
+ },
+
+ changeFolder: function(ob)
+ {
+ var fid = this.getFolderId(ob.m),
+ fdiv = $(fid).down('DIV'),
+ oldexpand = fdiv && fdiv.hasClassName('col');
+ this.deleteFolderElt(fid, !ob.ch);
+ if (ob.co && this.folder == ob.m) {
+ this.go('folder:INBOX');
+ }
+ this.createFolder(ob);
+ if (ob.ch && oldexpand) {
+ fdiv.removeClassName('exp').addClassName('col');
+ }
+ },
+
+ deleteFolderElt: function(fid, sub)
+ {
+ var f = $(fid), submbox;
+ if (!f) {
+ return;
+ }
+
+ if (sub) {
+ submbox = $(this.getSubFolderId(fid));
+ if (submbox) {
+ submbox.remove();
+ }
+ }
+ [ DragDrop.Drags.getDrag(fid), DragDrop.Drops.getDrop(fid) ].compact().invoke('destroy');
+ this._removeMouseEvents(f);
+ if (this.viewport) {
+ this.viewport.deleteView(fid);
+ }
+ f.remove();
+ },
+
+ _sizeFolderlist: function()
+ {
+ var nf = $('normalfolders');
+ nf.setStyle({ height: (document.viewport.getHeight() - nf.cumulativeOffset()[1]) + 'px' });
+ },
+
+ toggleSubscribed: function()
+ {
+ this.showunsub = !this.showunsub;
+ $('foldersLoading').show();
+ $('foldersSidebar').hide();
+ $('ctx_folderopts_sub', 'ctx_folderopts_unsub').invoke('toggle');
+
+ // TODO - Only do for unsub -> sub switch
+ [ $('specialfolders').childElements(), $('dropbase').nextSiblings() ].flatten().each(function(elt) {
+ this.deleteFolderElt(elt.readAttribute('id'), true);
+ }, this);
+
+ DimpCore.doAction('ListFolders', { unsub: Number(this.showunsub) }, null, this._folderLoadCallback.bind(this));
+ },
+
+ subscribeFolder: function(f, sub)
+ {
+ var fid = this.getFolderId(f);
+ DimpCore.doAction('Subscribe', { view: f, sub: Number(sub) });
+
+ if (this.showunsub) {
+ [ $(fid) ].invoke(sub ? 'removeClassName' : 'addClassName', 'unsubFolder');
+ } else if (!sub) {
+ this.deleteFolderElt(fid);
+ }
+ },
+
+ /* Flag actions for message list. */
+ _getFlagSelection: function(opts)
+ {
+ var vs;
+
+ if (opts.vs) {
+ vs = opts.vs;
+ } else if (opts.index) {
+ if (opts.mailbox) {
+ vs = this.viewport.getSelection().search({ imapuid: { equal: [ opts.index ] }, view: { equal: [ opts.mailbox ] } });
+ if (!vs.size() && opts.mailbox != this.folder) {
+ vs = this.viewport.getSelection(opts.mailbox).search({ imapuid: { equal: [ opts.index ] } });
+ }
+ } else {
+ vs = this.viewport.createSelection('dataob', opts.index);
+ }
+ } else {
+ vs = this.viewport.getSelected();
+ }
+
+ return vs;
+ },
+
+ _doMsgAction: function(type, opts, args)
+ {
+ var vs = this._getFlagSelection(opts);
+
+ if (vs.size()) {
+ // This needs to be synchronous Ajax if we are calling from a
+ // popup window because Mozilla will not correctly call the
+ // callback function if the calling window has been closed.
+ DimpCore.doAction(type, this.viewport.addRequestParams(args), vs, this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)), { asynchronous: !(opts.index && opts.mailbox) });
+ return vs;
+ }
+
+ return false;
+ },
+
+ // spam = (boolean) True for spam, false for innocent
+ // opts = 'index', 'mailbox'
+ reportSpam: function(spam, opts)
+ {
+ opts = opts || {};
+ if (this._doMsgAction('ReportSpam', opts, { spam: spam })) {
+ // Indicate to the user that something is happening (since spam
+ // reporting may not be instantaneous).
+ this.loadingImg('viewport', true);
+ }
+ },
+
+ // blacklist = (boolean) True for blacklist, false for whitelist
+ // opts = 'index', 'mailbox'
+ blacklist: function(blacklist, opts)
+ {
+ opts = opts || {};
+ this._doMsgAction('Blacklist', opts, { blacklist: blacklist });
+ },
+
+ // opts = 'index', 'mailbox'
+ deleteMsg: function(opts)
+ {
+ opts = opts || {};
+ var vs = this._getFlagSelection(opts);
+
+ // Make sure that any given row is not deleted more than once. Need to
+ // explicitly mark here because message may already be flagged deleted
+ // when we load page (i.e. switching to using trash folder).
+ vs = vs.search({ isdel: { not: [ true ] } });
+ if (!vs.size()) {
+ return;
+ }
+ vs.set({ isdel: true });
+
+ opts.vs = vs;
+
+ this._doMsgAction('DeleteMessage', opts, {});
+ this.updateFlag(vs, '\\deleted', true);
+ },
+
+ // flag = (string) IMAP flag name
+ // set = (boolean) True to set flag
+ // opts = (Object) 'index', 'mailbox', 'noserver'
+ flag: function(flag, set, opts)
+ {
+ opts = opts || {};
+ var flags = [ (set ? '' : '-') + flag ],
+ vs = this._getFlagSelection(opts);
+
+ if (!vs.size()) {
+ return;
+ }
+
+ switch (flag) {
+ case '\\answered':
+ if (set) {
+ this.updateFlag(vs, '\\flagged', false);
+ flags.push('-\\flagged');
+ }
+ break;
+
+ case '\\deleted':
+ vs.set({ isdel: false });
+ break;
+
+ case '\\seen':
+ vs.get('dataob').each(function(s) {
+ this.updateSeenUID(s, set);
+ }, this);
+ break;
+ }
+
+ this.updateFlag(vs, flag, set);
+ if (!opts.noserver) {
+ DimpCore.doAction('FlagMessage', { flags: flags.toJSON(), view: this.folder }, vs);
+ }
+ },
+
+ // type = (string) 'seen' or 'unseen'
+ // mbox = (string) The mailbox to flag
+ flagAll: function(type, set, mbox)
+ {
+ DimpCore.doAction('FlagAll', { flags: [ type ].toJSON(), set: Number(set), view: mbox }, null, this.bcache.get('flagAC') || this.bcache.set('flagAC', this._flagAllCallback.bind(this)));
+ },
+
+ hasFlag: function(f, r)
+ {
+ return r.flag && this.convertFlag(f, r.flag.include(f));
+ },
+
+ convertFlag: function(f, set)
+ {
+ /* For some flags, we need to do an inverse match (e.g. knowing a
+ * message is SEEN is not as important as knowing the message lacks
+ * the SEEN FLAG). This function will determine if, for a given flag,
+ * the inverse action should be taken on it. */
+ return DIMP.conf.flags[f].n ? !set : set;
+ },
+
+ updateFlag: function(vs, flag, add)
+ {
+ add = this.convertFlag(flag, add);
+
+ vs.get('dataob').each(function(ob) {
+ this._updateFlag(ob, flag, add);
+
+ /* If this is a search mailbox, also need to update flag in base
+ * view, if it is in the buffer. */
+ if (this.isSearch()) {
+ var tmp = this.viewport.getSelection(ob.view).search({ imapuid: { equal: [ ob.imapuid ] }, view: { equal: [ ob.view ] } });
+ if (tmp.size()) {
+ this._updateFlag(tmp.get('dataob').first(), flag, add);
+ }
+ }
+ }, this);
+ },
+
+ _updateFlag: function(ob, flag, add)
+ {
+ ob.flag = ob.flag
+ ? ob.flag.without(flag)
+ : [];
+
+ if (add) {
+ ob.flag.push(flag);
+ }
+
+ this.viewport.updateRow(ob);
+ },
+
+ /* Miscellaneous folder actions. */
+ purgeDeleted: function()
+ {
+ DimpCore.doAction('PurgeDeleted', this.viewport.addRequestParams({}), null, this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)));
+ },
+
+ modifyPoll: function(folder, add)
+ {
+ DimpCore.doAction('ModifyPoll', { view: folder, add: Number(add) }, null, this.bcache.get('modifyPFC') || this.bcache.set('modifyPFC', this._modifyPollCallback.bind(this)));
+ },
+
+ _modifyPollCallback: function(r)
+ {
+ r = r.response;
+ var f = r.folder, fid, p = { response: { poll: {} } };
+ fid = $(this.getFolderId(f));
+
+ if (r.add) {
+ p.response.poll[f] = r.poll.u;
+ fid.writeAttribute('u', 0);
+ } else {
+ p.response.poll[f] = 0;
+ }
+
+ this._pollCallback(p);
+
+ if (!r.add) {
+ fid.removeAttribute('u');
+ }
+ },
+
+ loadingImg: function(id, show)
+ {
+ var c;
+
+ if (show) {
+ $(id + 'Loading').clonePosition(id == 'viewport' ? 'msgList' : 'splitBar', { setHeight: false, setWidth: false }).show();
+ c = 'progress';
+ } else {
+ Effect.Fade(id + 'Loading', { duration: 0.2 });
+ c = 'default';
+ }
+ $(document.body).setStyle({ cursor: c });
+ },
+
+ // p = (element) Parent element
+ // c = (element) Child element
+ isSubfolder: function(p, c)
+ {
+ var sf = $(this.getSubFolderId(p.identify()));
+ return sf && c.descendantOf(sf);
+ },
+
+ /* Pref updating function. */
+ _updatePrefs: function(pref, value)
+ {
+ new Ajax.Request(DimpCore.addURLParam(DIMP.conf.URI_PREFS), { parameters: { app: 'imp', pref: pref, value: value } });
+ },
+
+ /* Onload function. */
+ onDomLoad: function()
+ {
+ DimpCore.init();
+
+ var DM = DimpCore.DMenu;
+
+ /* Register global handlers now. */
+ document.observe('keydown', this.keydownHandler.bindAsEventListener(this));
+
+ /* Limit to folders sidebar only. */
+ $('foldersSidebar').observe('mouseover', this.mouseoverHandler.bindAsEventListener(this));
+
+ /* Limit to msgList only. */
+ $('msgList').observe('dblclick', this.dblclickHandler.bindAsEventListener(this));
+
+ $('dimpLoading').hide();
+ $('dimpPage').show();
+
+ /* Create the folder list. Any pending notifications will be caught
+ * via the return from this call. */
+ DimpCore.doAction('ListFolders', {}, null, this._folderLoadCallback.bind(this));
+
+ /* Start message list loading as soon as possible. */
+ if (Horde.dhtmlHistory.initialize()) {
+ Horde.dhtmlHistory.addListener(this.go.bind(this));
+ }
+
+ /* Initialize the starting page if necessary. addListener() will have
+ * already fired if there is a current location so only do a go()
+ * call if there is no current location. */
+ if (!Horde.dhtmlHistory.getCurrentLocation()) {
+ if (DIMP.conf.login_view == 'inbox') {
+ this.go('folder:INBOX');
+ } else {
+ this.go('portal');
+ if (DIMP.conf.background_inbox) {
+ this.loadMailbox('INBOX', { background: true });
+ }
+ }
+ }
+
+ this._setFilterText(true);
+
+ /* Add popdown menus. Check for disabled compose at the same time. */
+ this._addMouseEvents({ id: 'button_other', type: 'otheractions' }, $('button_other'));
+ this._addMouseEvents({ id: 'folderopts', type: 'folderopts' }, $('folderopts').down(1));
+
+ DM.addSubMenu('ctx_message_reply', 'ctx_reply');
+ [ 'ctx_message_', 'oa_', 'ctx_draft_' ].each(function(i) {
+ if ($(i + 'setflag')) {
+ DM.addSubMenu(i + 'setflag', 'ctx_flag');
+ DM.addSubMenu(i + 'unsetflag', 'ctx_flag');
+ }
+ });
+
+ if (DIMP.conf.disable_compose) {
+ $('button_reply', 'button_forward').compact().invoke('up', 'SPAN').concat($('button_compose', 'composelink', 'ctx_contacts_new')).compact().invoke('remove');
+ } else {
+ this._addMouseEvents({ id: 'button_reply', type: 'reply' }, $('button_reply'));
+ DM.disable('button_reply_img', true, true);
+ }
+
+ new Drop('dropbase', this._folderDropConfig);
+
+ if (DIMP.conf.toggle_pref) {
+ this._toggleHeaders($('th_expand'));
+ }
+
+ this._resizeIE6();
+
+ /* Remove unavailable menu items. */
+ if (!$('GrowlerLog')) {
+ $('alertsloglink').remove();
+ }
+
+ /* Check for new mail. */
+ this.setPoll();
+
+ /* Init quicksearch. */
+ if ($('qsearch')) {
+ $('qsearch_input').observe('blur', this._quicksearchOnBlur.bind(this));
+ this._addMouseEvents({ id: 'qsearch_icon', left: true, offset: 'qsearch', type: 'qsearchopts' });
+ }
+
+ if (DimpCore.is_ie6) {
+ /* Disable text selection in preview pane for IE 6. */
+ document.observe('selectstart', Event.stop);
+ Event.observe(window, 'resize', this._resizeIE6.bind(this));
+
+ /* Since IE 6 doesn't support hover over non-links, use javascript
+ * events to replicate mouseover CSS behavior. */
+ $('dimpbarActions', 'serviceActions', 'applicationfolders', 'specialfolders', 'normalfolders').compact().invoke('select', 'LI').flatten().compact().each(function(e) {
+ e.observe('mouseover', e.addClassName.curry('over')).observe('mouseout', e.removeClassName.curry('over'));
+ });
+
+ /* These are links, but they have no href attribute. Hovering
+ * requires something in href on IE6. */
+ $$('.context A').each(function(e) {
+ e.writeAttribute('href', '');
+ });
+ }
+ },
+
+ // IE 6 width fixes (See Bug #6793)
+ _resizeIE6: function()
+ {
+ if (DimpCore.is_ie6) {
+ var tmp = parseInt($('sidebarPanel').getStyle('width'), 10),
+ tmp1 = document.viewport.getWidth() - tmp - 30;
+ $('normalfolders').setStyle({ width: tmp + 'px' });
+ $('dimpmain').setStyle({ width: tmp1 + 'px' });
+ $('msglist').setStyle({ width: (tmp1 - 5) + 'px' });
+ $('msgBody').setStyle({ width: (tmp1 - 25) + 'px' });
+ tmp = $('dimpmain_portal').down('IFRAME');
+ if (tmp) {
+ this._resizeIE6Iframe(tmp);
+ }
+ }
+ },
+
+ _resizeIE6Iframe: function(iframe)
+ {
+ if (DimpCore.is_ie6) {
+ iframe.setStyle({ width: $('dimpmain').getStyle('width'), height: (document.viewport.getHeight() - 20) + 'px' });
+ }
+ }
+
+};
+
+/* Need to add after DimpBase is defined. */
+DimpBase._msgDragConfig = {
+ scroll: 'normalfolders',
+ threshold: 5,
+ caption: DimpBase.dragCaption.bind(DimpBase),
+ onStart: function(d, e) {
+ var args = { right: e.isRightClick() },
+ id = d.element.id;
+
+ d.selectIfNoDrag = false;
+
+ // Handle selection first.
+ if (!args.right && (e.ctrlKey || e.metaKey)) {
+ DimpBase.msgSelect(id, $H({ ctrl: true }).merge(args).toObject());
+ } else if (e.shiftKey) {
+ DimpBase.msgSelect(id, $H({ shift: true }).merge(args).toObject());
+ } else if (e.element().hasClassName('msCheck')) {
+ DimpBase.msgSelect(id, { ctrl: true, right: true });
+ } else if (DimpBase.isSelected('domid', id)) {
+ if (!args.right && DimpBase.selectedCount()) {
+ d.selectIfNoDrag = true;
+ }
+ } else {
+ DimpBase.msgSelect(id, args);
+ }
+ },
+ onEnd: function(d, e) {
+ if (d.selectIfNoDrag && !d.wasDragged) {
+ DimpBase.msgSelect(d.element.id, { right: e.isRightClick() });
+ }
+ }
+};
+
+DimpBase._folderDragConfig = {
+ ghosting: true,
+ offset: { x: 15, y: 0 },
+ scroll: 'normalfolders',
+ threshold: 5,
+ onDrag: function(d, e) {
+ if (!d.wasDragged) {
+ $('folderopts').hide();
+ $('dropbase').show();
+ d.ghost.removeClassName('on');
+ }
+ },
+ onEnd: function(d, e) {
+ if (d.wasDragged) {
+ $('folderopts').show();
+ $('dropbase').hide();
+ }
+ }
+};
+
+DimpBase._folderDropConfig = {
+ caption: function(drop, drag, e) {
+ var m,
+ d = drag.readAttribute('l'),
+ ftype = drop.readAttribute('ftype'),
+ l = drop.readAttribute('l');
+
+ if (drop == $('dropbase')) {
+ return DIMP.text.moveto.replace(/%s/, d).replace(/%s/, DIMP.text.baselevel);
+ } else {
+ switch (e.type) {
+ case 'mousemove':
+ m = (e.ctrlKey) ? DIMP.text.copyto : DIMP.text.moveto;
+ break;
+
+ case 'keydown':
+ /* Can't use ctrlKey here since different browsers handle
+ * the ctrlKey in different ways when it comes to firing
+ * keybaord events. */
+ m = (e.keyCode == 17) ? DIMP.text.copyto : DIMP.text.moveto;
+ break;
+
+ case 'keyup':
+ if (e.keyCode == 17) {
+ m = DIMP.text.moveto;
+ } else {
+ m = (e.ctrlKey) ? DIMP.text.copyto : DIMP.text.moveto;
+ }
+ break;
+ }
+ if (drag.hasClassName('folder')) {
+ return (ftype != 'special' && !DimpBase.isSubfolder(drag, drop)) ? m.replace(/%s/, d).replace(/%s/, l) : '';
+ } else {
+ return ftype != 'container' ? m.replace(/%s/, DimpBase.dragCaption()).replace(/%s/, l) : '';
+ }
+ }
+ },
+ keypress: true,
+ onDrop: DimpBase._folderDropHandler.bind(DimpBase)
+};
+
+/* Need to register a callback function for doAction to catch viewport
+ * information returned from the server. */
+DimpCore.onDoActionComplete = function(r) {
+ if (DimpBase.viewport) {
+ DimpBase.viewport.parseJSONResponse(r);
+ }
+};
+
+/* Click handler. */
+DimpCore.clickHandler = DimpCore.clickHandler.wrap(DimpBase.clickHandler.bind(DimpBase));
+
+/* ContextSensitive functions. */
+DimpCore.contextOnClick = DimpCore.contextOnClick.wrap(DimpBase.contextOnClick.bind(DimpBase));
+DimpCore.contextOnShow = DimpCore.contextOnShow.wrap(DimpBase.contextOnShow.bind(DimpBase));
+
+/* Initialize onload handler. */
+document.observe('dom:loaded', DimpBase.onDomLoad.bind(DimpBase));
--- /dev/null
+/**
+ * DimpCore.js - Dimp UI application logic.
+ *
+ * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+/* DimpCore object. */
+var DimpCore = {
+ // Vars used and defaulting to null/false:
+ // DMenu, Growler, inAjaxCallback, is_init, is_logout,
+ // onDoActionComplete
+ growler_log: true,
+ is_ie6: false /*@cc_on || @_jscript_version < 5.7 @*/,
+ server_error: 0,
+
+ doActionOpts: {
+ onException: function(r, e) { DimpCore.debug('onException', e); },
+ onFailure: function(t, o) { DimpCore.debug('onFailure', t); },
+ evalJS: false,
+ evalJSON: true
+ },
+
+ debug: function(label, e)
+ {
+ if (!this.is_logout && DIMP.conf.debug) {
+ if (console && console.error) {
+ // Firebug error reporting.
+ console.error(label, e);
+ } else {
+ alert(label + ': ' + ((e instanceof Error && e.name && e.message) ? e.name + '-' + e.message : Object.inspect(e)) + (e.lineNumber ? ' (Line #' + e.lineNumber + ')' : ''));
+ }
+ }
+ },
+
+ // Convert object to an IMP UID Range string. See IMP::toRangeString()
+ // ob = (object) mailbox name as keys, values are array of uids.
+ toRangeString: function(ob)
+ {
+ var str = '';
+
+ $H(ob).each(function(o) {
+ if (!o.value.size()) {
+ return;
+ }
+
+ var u = o.value.numericSort(),
+ first = u.shift(),
+ last = first,
+ out = [];
+
+ u.each(function(k) {
+ if (last + 1 == k) {
+ last = k;
+ } else {
+ out.push(first + (last == first ? '' : (':' + last)));
+ first = last = k;
+ }
+ });
+ out.push(first + (last == first ? '' : (':' + last)));
+ str += '{' + o.key.length + '}' + o.key + out.join(',');
+ });
+
+ return str;
+ },
+
+ // Parses an IMP UID Range string. See IMP::parseRangeString()
+ // str = (string) An IMP UID range string.
+ parseRangeString: function(str)
+ {
+ var count, end, i, mbox,
+ mlist = {},
+ uids = [];
+ str = str.strip();
+
+ while (!str.blank()) {
+ if (!str.startsWith('{')) {
+ break;
+ }
+ i = str.indexOf('}');
+ count = Number(str.substr(1, i - 1));
+ mbox = str.substr(i + 1, count);
+ i += count + 1;
+ end = str.indexOf('{', i);
+ if (end == -1) {
+ uidstr = str.substr(i);
+ str = '';
+ } else {
+ uidstr = str.substr(i, end - i);
+ str = str.substr(end);
+ }
+
+ uidstr.split(',').each(function(e) {
+ var r = e.split(':');
+ if (r.size() == 1) {
+ uids.push(Number(e));
+ } else {
+ uids = uids.concat($A($R(Number(r[0]), Number(r[1]))));
+ }
+ });
+
+ mlist[mbox] = uids;
+ }
+
+ return mlist;
+ },
+
+ /* 'action' -> if action begins with a '*', the exact string will be used
+ * instead of sending the action to the IMP handler. */
+ doAction: function(action, params, uids, callback, opts)
+ {
+ var b, tmp = {};
+
+ opts = Object.extend(this.doActionOpts, opts || {});
+ params = $H(params);
+ action = action.startsWith('*')
+ ? action.substring(1)
+ : DIMP.conf.URI_AJAX + '/' + action;
+
+ if (uids) {
+ if (uids.viewport_selection) {
+ b = uids.getBuffer();
+ if (b.getMetaData('search')) {
+ uids.get('dataob').each(function(r) {
+ if (!tmp[r.view]) {
+ tmp[r.view] = [];
+ }
+ tmp[r.view].push(r.imapuid);
+ });
+ } else {
+ tmp[b.getView()] = uids.get('uid');
+ }
+ uids = tmp;
+ }
+ params.set('uid', this.toRangeString(uids));
+ }
+
+ opts.parameters = this.addRequestParams(params);
+ opts.onComplete = function(t, o) { this.doActionComplete(t, callback); }.bind(this);
+ new Ajax.Request(action, opts);
+ },
+
+ // params - (Hash)
+ addRequestParams: function(params)
+ {
+ var p = params.clone();
+
+ if (DIMP.conf.SESSION_ID) {
+ p.update(DIMP.conf.SESSION_ID.toQueryParams());
+ }
+
+ return p;
+ },
+
+ doActionComplete: function(request, callback)
+ {
+ this.inAjaxCallback = true;
+
+ if (!request.responseJSON) {
+ if (++this.server_error == 3) {
+ this.showNotifications([ { type: 'horde.error', message: DIMP.text.ajax_timeout } ]);
+ }
+ this.inAjaxCallback = false;
+ return;
+ }
+
+ var r = request.responseJSON;
+
+ if (!r.msgs) {
+ r.msgs = [];
+ }
+
+ if (r.response && Object.isFunction(callback)) {
+ try {
+ callback(r);
+ } catch (e) {
+ this.debug('doActionComplete', e);
+ }
+ }
+
+ if (this.server_error >= 3) {
+ r.msgs.push({ type: 'horde.success', message: DIMP.text.ajax_recover });
+ }
+ this.server_error = 0;
+
+ this.showNotifications(r.msgs);
+
+ if (r.response && this.onDoActionComplete) {
+ this.onDoActionComplete(r.response);
+ }
+
+ this.inAjaxCallback = false;
+ },
+
+ setTitle: function(title)
+ {
+ document.title = DIMP.conf.name + ' :: ' + title;
+ },
+
+ showNotifications: function(msgs)
+ {
+ if (!msgs.size() || this.is_logout) {
+ return;
+ }
+
+ msgs.find(function(m) {
+ var log = 0;
+
+ switch (m.type) {
+ case 'dimp.timeout':
+ this.logout(DIMP.conf.URI_TIMEOUT);
+ return true;
+
+ case 'horde.error':
+ case 'horde.message':
+ case 'horde.success':
+ case 'horde.warning':
+ log = 1;
+ // Fall through to below case.
+
+ case 'imp.reply':
+ case 'imp.forward':
+ case 'imp.redirect':
+ this.Growler.growl(m.message, {
+ className: m.type.replace('.', '-'),
+ life: 8,
+ log: log,
+ sticky: m.type == 'horde.error'
+ });
+ }
+ }, this);
+ },
+
+ compose: function(type, args)
+ {
+ var url = DIMP.conf.URI_COMPOSE;
+ args = args || {};
+ if (type) {
+ args.type = type;
+ }
+ this.popupWindow(this.addURLParam(url, args), 'compose' + new Date().getTime());
+ },
+
+ popupWindow: function(url, name)
+ {
+ if (!(window.open(url, name.replace(/\W/g, '_'), 'width=' + DIMP.conf.popup_width + ',height=' + DIMP.conf.popup_height + ',status=1,scrollbars=yes,resizable=yes'))) {
+ this.showNotifications([ { type: 'horde.warning', message: DIMP.text.popup_block } ]);
+ }
+ },
+
+ closePopup: function()
+ {
+ // Mozilla bug/feature: it will not close a browser window
+ // automatically if there is code remaining to be performed (or, at
+ // least, not here) unless the mouse is moved or a keyboard event
+ // is triggered after the callback is complete. (As of FF 2.0.0.3 and
+ // 1.5.0.11). So wait for the callback to complete before attempting
+ // to close the window.
+ if (this.inAjaxCallback) {
+ this.closePopup.bind(this).defer();
+ } else {
+ window.close();
+ }
+ },
+
+ logout: function(url)
+ {
+ this.is_logout = true;
+ this.redirect(url || (DIMP.conf.URI_AJAX + '/LogOut'));
+ },
+
+ redirect: function(url, force)
+ {
+ var ptr = parent.frames.horde_main ? parent : window;
+ ptr.location = this.addURLParam(url);
+ if (force) {
+ setTimeout(function() { ptr.location.reload() }, 300);
+ }
+ },
+
+ /* Add dropdown menus to addresses. */
+ buildAddressLinks: function(alist, elt)
+ {
+ var base, tmp,
+ cnt = alist.size();
+
+ if (cnt > 15) {
+ tmp = $('largeaddrspan').cloneNode(true).writeAttribute('id', 'largeaddrspan_active');
+ elt.insert(tmp);
+ base = tmp.down('.dispaddrlist');
+ tmp = tmp.down(1);
+ tmp.setText(tmp.getText().replace('%d', cnt));
+ } else {
+ base = elt;
+ }
+
+ alist.each(function(o, i) {
+ var a;
+ if (o.raw) {
+ a = o.raw;
+ } else {
+ a = new Element('A', { className: 'address', personal: o.personal, email: o.inner, address: (o.personal ? (o.personal + ' <' + o.inner + '>') : o.inner) });
+ if (o.personal) {
+ a.writeAttribute({ title: o.inner }).insert(o.personal.escapeHTML());
+ } else {
+ a.insert(o.inner.escapeHTML());
+ }
+ this.DMenu.addElement(a.identify(), 'ctx_contacts', { offset: a, left: true });
+ }
+ base.insert(a);
+ if (i + 1 != cnt) {
+ base.insert(', ');
+ }
+ }, this);
+
+ return elt;
+ },
+
+ /* Add message log info to message view. */
+ updateMsgLog: function(log)
+ {
+ var tmp = '';
+ log.each(function(entry) {
+ tmp += '<li><span class="iconImg imp-' + entry.t + '"></span>' + entry.m + '</li>';
+ });
+ $('msgloglist').down('UL').update(tmp);
+ },
+
+ /* Removes event handlers from address links. */
+ removeAddressLinks: function(id)
+ {
+ id.select('.address').each(function(elt) {
+ this.DMenu.removeElement(elt.identify());
+ }, this);
+ },
+
+ addURLParam: function(url, params)
+ {
+ var q = url.indexOf('?');
+ params = $H(params);
+
+ if (DIMP.conf.SESSION_ID) {
+ params.update(DIMP.conf.SESSION_ID.toQueryParams());
+ }
+
+ if (q != -1) {
+ params.update(url.toQueryParams());
+ url = url.substring(0, q);
+ }
+
+ return params.size() ? (url + '?' + params.toQueryString()) : url;
+ },
+
+ reloadMessage: function(params)
+ {
+ if (typeof DimpFullmessage != 'undefined') {
+ window.location = this.addURLParam(document.location.href, params);
+ } else {
+ DimpBase.loadPreview(null, params);
+ }
+ },
+
+ /* Mouse click handler. */
+ clickHandler: function(e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = e.element(), id, tmp;
+
+ while (Object.isElement(elt)) {
+ id = elt.readAttribute('id');
+
+ switch (id) {
+ case 'msg_print':
+ window.print();
+ break;
+
+ case 'alertsloglink':
+ $('alertsloglink').down('A').update(this.Growler.toggleLog() ? DIMP.text.hidealog : DIMP.text.showalog);
+ break;
+
+ case 'largeaddrspan_active':
+ tmp = elt.down();
+ [ tmp.down(), tmp.down(1), tmp.next() ].invoke('toggle');
+ break;
+
+ default:
+ // CSS class based matching
+ if (elt.hasClassName('unblockImageLink')) {
+ IMP.unblockImages(e);
+ } else if (elt.hasClassName('toggleQuoteShow')) {
+ [ elt, elt.next() ].invoke('toggle');
+ Effect.BlindDown(elt.next(1), { duration: 0.2, queue: { position: 'end', scope: 'showquote', limit: 2 } });
+ } else if (elt.hasClassName('toggleQuoteHide')) {
+ [ elt, elt.previous() ].invoke('toggle');
+ Effect.BlindUp(elt.next(), { duration: 0.2, queue: { position: 'end', scope: 'showquote', limit: 2 } });
+ } else if (elt.hasClassName('pgpVerifyMsg')) {
+ elt.replace(DIMP.text.verify);
+ DimpCore.reloadMessage({ pgp_verify_msg: 1 });
+ e.stop();
+ } else if (elt.hasClassName('smimeVerifyMsg')) {
+ elt.replace(DIMP.text.verify);
+ DimpCore.reloadMessage({ smime_verify_msg: 1 });
+ e.stop();
+ }
+ break;
+ }
+
+ elt = elt.up();
+ }
+ },
+
+ // By default, no context onShow action
+ contextOnShow: Prototype.emptyFunction,
+
+ contextOnClick: function(elt, baseelt, menu)
+ {
+ switch (elt.readAttribute('id')) {
+ case 'ctx_contacts_new':
+ this.compose('new', { to: baseelt.readAttribute('address') });
+ break;
+
+ case 'ctx_contacts_add':
+ this.doAction('AddContact', { name: baseelt.readAttribute('personal'), email: baseelt.readAttribute('email') }, null, true);
+ break;
+ }
+ },
+
+ /* DIMP initialization function. */
+ init: function()
+ {
+ if (this.is_init) {
+ return;
+ }
+ this.is_init = true;
+
+ if (typeof ContextSensitive != 'undefined') {
+ this.DMenu = new ContextSensitive({
+ onClick: this.contextOnClick.bind(this),
+ onShow: this.contextOnShow.bind(this)
+ });
+ }
+
+ /* Don't do additional onload stuff if we are in a popup. We need a
+ * try/catch block here since, if the page was loaded by an opener
+ * out of this current domain, this will throw an exception. */
+ try {
+ if (parent.opener &&
+ parent.opener.location.host == window.location.host &&
+ parent.opener.DimpCore) {
+ DIMP.baseWindow = parent.opener.DIMP.baseWindow || parent.opener;
+ }
+ } catch (e) {}
+
+ /* Add Growler notification handler. */
+ this.Growler = new Growler({
+ location: 'br',
+ log: this.growler_log,
+ noalerts: DIMP.text.noalerts
+ });
+
+ /* Add click handler. */
+ document.observe('click', DimpCore.clickHandler.bindAsEventListener(DimpCore));
+ }
+
+};
--- /dev/null
+/**
+ * DimpSlider.js - A minimalist library to create a slider that acts like a
+ * browser's native scrollbar.
+ * Requires prototype.js 1.6.0.2+
+ *
+ * Adapted from script.aculo.us slider.js v1.8.0
+ * (c) 2005-2007 Marty Haught, Thomas Fuchs
+ * http://script.aculo.us/
+ *
+ * The original script was freely distributable under the terms of an
+ * MIT-style license.
+ *
+ * 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 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.
+ *
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Michael Slusarz <slusarz@curecanti.org>
+ */
+
+var DimpSlider = Class.create({
+ value: 0,
+
+ initialize: function(track, options)
+ {
+ this.track = $(track);
+ this.options = Object.extend({
+ buttonclass: null,
+ cursorclass: null,
+ pagesize: 0,
+ totalsize: 0
+ }, options || {});
+
+ this.handle = new Element('DIV', { className: this.options.cursorclass }).makePositioned();
+ this.track.insert(this.handle);
+
+ if (this.options.buttonclass) {
+ this.sbup = new Element('DIV', { className: this.options.buttonclass.up });
+ this.sbdown = new Element('DIV', { className: this.options.buttonclass.down }).makePositioned();
+ this.handle.insert({ before: this.sbup, after: this.sbdown });
+ [ this.sbup, this.sbdown ].invoke('observe', 'mousedown', this._arrowClick.bindAsEventListener(this));
+ }
+
+ this.sbdownsize = this.sbupsize = this.value = 0;
+ this.active = this.dragging = false;
+
+ if (this._showScroll()) {
+ this._initScroll();
+ }
+
+ this.eventMU = this._endDrag.bindAsEventListener(this);
+ this.eventMM = this._update.bindAsEventListener(this);
+
+ [ this.handle, this.track ].invoke('observe', 'mousedown', this._startDrag.bindAsEventListener(this));
+ },
+
+ _initScroll: function()
+ {
+ if (this.init) {
+ return false;
+ }
+ this.init = true;
+ this.track.show();
+ if (this.sbup) {
+ this.sbupsize = this.sbup.offsetHeight;
+ this.sbdownsize = this.sbdown.offsetHeight;
+ }
+ this._updateHandleLength();
+ return true;
+ },
+
+ _startDrag: function(e)
+ {
+ if (!e.isLeftClick()) {
+ return;
+ }
+
+ var dir,
+ hoffsets = this.handle.cumulativeOffset();
+
+ if (e.element() == this.track) {
+ dir = (e.pointerY() < hoffsets[1]) ? -1 : 1;
+ this.setScrollPosition(this.getValue() - dir + (this.options.pagesize * dir));
+ } else {
+ this.curroffsets = this.track.cumulativeOffset();
+ this.offsetY = e.pointerY() - hoffsets[1] + this.sbupsize;
+ this.active = true;
+
+ document.observe('mouseup', this.eventMU);
+ document.observe('mousemove', this.eventMM);
+ }
+
+ e.stop();
+ },
+
+ _update: function(e)
+ {
+ if (this.active) {
+ this.dragging = true;
+ this._setScrollPosition('px', Math.min(Math.max(0, e.pointerY() - this.offsetY - this.curroffsets[1]), this.handletop));
+ if (this.options.onSlide) {
+ this.options.onSlide();
+ }
+ if (Prototype.Browser.WebKit) {
+ window.scrollBy(0,0);
+ }
+ e.stop();
+ }
+ },
+
+ _endDrag: function(e)
+ {
+ if (this.active && this.dragging) {
+ this._updateFinished();
+ e.stop();
+
+ document.stopObserving('mouseup', this.eventMU);
+ document.stopObserving('mousemove', this.eventMM);
+ }
+ this.active = this.dragging = false;
+ },
+
+ _arrowClick: function(e)
+ {
+ this.setScrollPosition(this.getValue() + ((e.element() == this.sbup) ? -1 : 1));
+ },
+
+ _updateFinished: function()
+ {
+ if (this.options.onChange) {
+ this.options.onChange();
+ }
+ },
+
+ updateHandleLength: function(pagesize, totalsize)
+ {
+ this.options.pagesize = pagesize;
+ this.options.totalsize = totalsize;
+ if (!this._showScroll()) {
+ this.value = 0;
+ this.track.hide();
+ return;
+ }
+ if (!this._initScroll()) {
+ this.track.show();
+ this._updateHandleLength();
+ }
+ },
+
+ _updateHandleLength: function()
+ {
+ var t = this.track.offsetHeight - this.sbupsize - this.sbdownsize;
+
+ // Minimum handle size = 10px
+ this.handle.setStyle({ height: Math.max(10, Math.round((this.options.pagesize / this.options.totalsize) * t)) + 'px' });
+ this.handletop = t - this.handle.offsetHeight;
+ if (this.sbdown) {
+ this.sbdown.setStyle({ top: this.handletop + 'px' });
+ }
+ this._setScrollPosition('val', this.getValue());
+ },
+
+ getValue: function()
+ {
+ return this.value;
+ },
+
+ setScrollPosition: function(val)
+ {
+ if (this._showScroll()) {
+ var oldval = this.getValue();
+ this._setScrollPosition('val', val);
+ if (oldval != this.getValue()) {
+ this._updateFinished();
+ }
+ }
+ },
+
+ _setScrollPosition: function(type, data)
+ {
+ this.value = (type == 'val')
+ ? Math.min(Math.max(0, data), this.options.totalsize - this.options.pagesize)
+ : Math.max(0, Math.round(Math.min(data, this.handletop) / this.handletop * (this.options.totalsize - this.options.pagesize)));
+ this.handlevalue = (type == 'px')
+ ? data
+ : Math.round(this.getValue() / (this.options.totalsize - this.options.pagesize) * this.handletop);
+ this.handle.setStyle({ top: this.handlevalue + 'px' });
+ },
+
+ _showScroll: function()
+ {
+ return (this.options.pagesize < this.options.totalsize);
+ }
+});
--- /dev/null
+/**
+ * ViewPort.js - Code to create a viewport window in a web browser.
+ *
+ * Usage:
+ * ======
+ * var viewport = new ViewPort({ options });
+ *
+ * Required options:
+ * -----------------
+ * ajax_url: (string) TODO
+ * Response: 'ViewPort'
+ * content: (Element/string) A DOM element/ID of the container to hold the
+ * viewport rows.
+ * template: (string) TODO DIV with 'vpData'
+ * Class: 'vpRow' 'vpRowSelected'
+ *
+ * Optional options:
+ * -----------------
+ * ajax_opts: (object) TODO
+ * buffer_pages: (integer) The number of viewable pages to send to the browser
+ * per server access when listing rows.
+ * empty_msg: (string) A string to display when the view is empty. Inserted in
+ * a SPAN element with class 'vpEmpty'.
+ * limit_factor: (integer) When browsing through a list, if a user comes
+ * within this percentage of the end of the current cached
+ * viewport, send a background request to the server to retrieve
+ * the next slice.
+ * page_size: (integer) Default page size to view on load.
+ * show_split_pane: (boolean) Show the split pane on load?
+ * split_bar: (Element/string) A DOM element/ID of the element used to display
+ * the split bar.
+ * split_pane: (Element/string) A DOM element/ID of the container to hold
+ * the split pane info.
+ * wait: (integer) How long, in seconds, to wait before displaying an
+ * informational message to users that the message list is still being
+ * built.
+ *
+ * Callbacks:
+ * ----------
+ * onAjaxRequest
+ * onAjaxResponse
+ * onCachedList
+ * onCacheUpdate
+ * onClear
+ * onContent
+ * onContentComplete
+ * onDeselect
+ * onEndFetch
+ * onFetch
+ * onSelect
+ * onSlide
+ * onSplitBarChange
+ * onWait
+ *
+ * Outgoing AJAX request has the following params (TODO):
+ * ------------------------------------------------------
+ * For a row request:
+ * request_id: (integer) TODO
+ * slice: (string)
+ *
+ * For a search request:
+ * request_id: (integer) TODO
+ * search: (JSON object)
+ * search_after: (integer)
+ * search_before: (integer)
+ *
+ * For a rangeslice request:
+ * rangeslice: (boolean)
+ * slice: (string)
+ *
+ * Incoming AJAX response has the following params (TODO):
+ * -------------------------------------------------------
+ * cacheid
+ * data
+ * label
+ * metadata (optional)
+ * request_id
+ * rangelist: TODO
+ * reset (optional) - If set, purges all cached data
+ * resetmd (optional) - If set, purges all user metadata
+ * rowlist
+ * rownum (optional)
+ * totalrows
+ * update (optional) - If set, update the rowlist instead of overwriting it.
+ * view
+ *
+ * Requires prototypejs 1.6+, DimpSlider.js, scriptaculous 1.8+ (effects.js
+ * only), and Horde's dragdrop2.js.
+ *
+ * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+/**
+ * ViewPort
+ */
+var ViewPort = Class.create({
+
+ initialize: function(opts)
+ {
+ this.opts = Object.extend({
+ buffer_pages: 5,
+ limit_factor: 35
+ }, opts);
+
+ this.opts.content = $(opts.content);
+ this.opts.split_pane = $(opts.split_pane);
+
+ this.scroller = new ViewPort_Scroller(this);
+ this.template = new Template(opts.template);
+
+ this.views = {};
+
+ this.split_bar_loc = opts.page_size;
+ this.show_split_pane = opts.show_split_pane;
+
+ this.isbusy = this.line_height = this.page_size = this.split_bar = null;
+ this.request_num = 1;
+
+ // Init empty string now.
+ this.empty_msg = new Element('SPAN', { className: 'vpEmpty' }).insert(opts.empty_msg);
+
+ // Set up AJAX response function.
+ this.ajax_response = this.opts.onAjaxResponse || this._ajaxRequestComplete.bind(this);
+
+ Event.observe(window, 'resize', this.onResize.bind(this));
+ },
+
+ // view = ID of view.
+ // search = (object) Search parameters
+ // background = Load view in background?
+ loadView: function(view, search, background)
+ {
+ var buffer, curr, init = true, opts = {}, ps;
+
+ this._clearWait();
+
+ // Need a page size before we can continue - this is what determines
+ // the slice size to request from the server.
+ if (this.page_size === null) {
+ ps = this.getPageSize(this.show_split_pane ? 'default' : 'max');
+ if (isNaN(ps)) {
+ return this.loadView.bind(this, view, search, background).defer();
+ }
+ this.page_size = ps;
+ }
+
+ if (this.view) {
+ if (!background) {
+ // Need to store current buffer to save current offset
+ buffer = this._getBuffer();
+ buffer.setMetaData({ offset: this.currentOffset() }, true);
+ this.views[this.view] = buffer;
+ }
+ init = false;
+ }
+
+ if (background) {
+ opts = { background: true, view: view };
+ } else {
+ if (!this.view) {
+ this.onResize(true);
+ } else if (this.view != view) {
+ this.active_req = null;
+ }
+ this.view = view;
+ }
+
+ if (curr = this.views[view]) {
+ this._updateContent(curr.getMetaData('offset') || 0, opts);
+ if (!background) {
+ this._ajaxRequest({ checkcache: 1 });
+ }
+ return;
+ }
+
+ if (!init) {
+ if (this.opts.onClear) {
+ this.opts.onClear(this.visibleRows());
+ }
+ this.opts.content.update();
+ this.scroller.clear();
+ }
+
+ this.views[view] = buffer = this._getBuffer(view, true);
+
+ if (search) {
+ opts.search = search;
+ } else {
+ opts.offset = 0;
+ }
+
+ opts.initial = 1;
+
+ this._fetchBuffer(opts);
+ },
+
+ // view = ID of view
+ deleteView: function(view)
+ {
+ delete this.views[view];
+ },
+
+ // rownum = (integer) Row number
+ // opts = (Object) [noupdate, top] TODO
+ scrollTo: function(rownum, opts)
+ {
+ var s = this.scroller;
+ opts = opts || {};
+
+ s.noupdate = opts.noupdate;
+
+ switch (this.isVisible(rownum)) {
+ case -1:
+ s.moveScroll(rownum - 1);
+ break;
+
+ case 0:
+ if (opts.top) {
+ s.moveScroll(rownum - 1);
+ }
+ break;
+
+ case 1:
+ s.moveScroll(Math.min(rownum, this.getMetaData('total_rows') - this.getPageSize() + 1));
+ break;
+ }
+
+ s.noupdate = false;
+ },
+
+ // rownum = Row number
+ isVisible: function(rownum)
+ {
+ var offset = this.currentOffset();
+ return (rownum < offset + 1)
+ ? -1
+ : ((rownum > (offset + this.getPageSize('current'))) ? 1 : 0);
+ },
+
+ // params = TODO
+ reload: function(params)
+ {
+ this._fetchBuffer({
+ offset: this.currentOffset(),
+ params: $H(params).merge({ purge: true })
+ });
+ },
+
+ // vs = (Viewport_Selection) A Viewport_Selection object.
+ // opts = (object) TODO [cacheid, noupdate, view]
+ remove: function(vs, opts)
+ {
+ if (!vs.size()) {
+ return;
+ }
+
+ if (this.isbusy) {
+ this.remove.bind(this, vs, opts).defer();
+ return;
+ }
+
+ this.isbusy = true;
+ opts = opts || {};
+
+ var args,
+ i = 0,
+ visible = vs.get('div'),
+ vsize = visible.size();
+
+ this.deselect(vs);
+
+ if (opts.cacheid) {
+ this._getBuffer(opts.view).setMetaData({ cacheid: opts.cacheid }, true);
+ }
+
+ // If we have visible elements to remove, only call refresh after
+ // the last effect has finished.
+ if (vsize) {
+ // Set 'to' to a value slightly above 0 to prevent Effect.Fade
+ // from auto hiding. Hiding is unnecessary, since we will be
+ // removing from the document shortly.
+ args = { duration: 0.25, to: 0.01 };
+ visible.each(function(v) {
+ if (++i == vsize) {
+ args.afterFinish = this._removeids.bind(this, vs, opts);
+ }
+ Effect.Fade(v, args);
+ }, this);
+ } else {
+ this._removeids(vs, opts);
+ }
+ },
+
+ // vs = (Viewport_Selection) A Viewport_Selection object.
+ // opts = (object) TODO [noupdate, view]
+ _removeids: function(vs, opts)
+ {
+ this._getBuffer(opts.view).setMetaData({ total_rows: this.getMetaData('total_rows', opts.view) - vs.size() }, true);
+
+ if (this.opts.onClear) {
+ this.opts.onClear(vs.get('div').compact());
+ }
+
+ this._getBuffer().remove(vs.get('rownum'));
+
+ if (this.opts.onCacheUpdate) {
+ this.opts.onCacheUpdate(opts.view || this.view);
+ }
+
+ if (!opts.noupdate) {
+ this.requestContentRefresh(this.currentOffset());
+ }
+
+ this.isbusy = false;
+ },
+
+ // nowait = (boolean) TODO
+ onResize: function(nowait)
+ {
+ if (!this.opts.content.visible()) {
+ return;
+ }
+
+ if (this.resizefunc) {
+ clearTimeout(this.resizefunc);
+ }
+
+ if (nowait) {
+ this._onResize();
+ } else {
+ this.resizefunc = this._onResize.bind(this).delay(0.1);
+ }
+ },
+
+ _onResize: function()
+ {
+ // This is needed for IE 6 - or else horizontal scrolling can occur.
+ if (!this.opts.content.offsetHeight) {
+ return this._onResize.bind(this).defer();
+ }
+
+ var diff, h, setpane,
+ c = $(this.opts.content),
+ de = document.documentElement,
+ lh = this._getLineHeight();
+
+ // Get split pane dimensions
+ if (this.opts.split_pane) {
+ if (this.show_split_pane) {
+ if (!this.opts.split_pane.visible()) {
+ this._initSplitBar();
+ if (this.split_bar_loc &&
+ this.split_bar_loc > 0) {
+ this.split_bar_loc = this.page_size = Math.min(this.split_bar_loc, this.getPageSize('splitmax'));
+ } else {
+ this.page_size = this.getPageSize('default');
+ }
+ }
+ setpane = true;
+ } else if (this.opts.split_pane.visible()) {
+ this.split_bar_loc = this.page_size;
+ [ this.opts.split_pane, this.split_bar ].invoke('hide');
+ }
+ }
+
+ if (!setpane) {
+ this.page_size = this.getPageSize('max');
+ }
+
+ // Do some magic to ensure we never cause a horizontal scroll.
+ h = lh * this.page_size;
+ c.setStyle({ height: h + 'px' });
+ if (setpane) {
+ this.opts.split_pane.setStyle({ height: (this._getMaxHeight() - h - lh) + 'px' }).show();
+ this.split_bar.show();
+ } else if (diff = de.scrollHeight - de.clientHeight) {
+ c.setStyle({ height: (lh * (this.page_size - 1)) + 'px' });
+ }
+
+ this.scroller.onResize();
+ },
+
+ // offset = (integer) TODO
+ requestContentRefresh: function(offset)
+ {
+ if (!this._updateContent(offset)) {
+ return false;
+ }
+
+ var limit = this._getBuffer().isNearingLimit(offset);
+ if (limit) {
+ this._fetchBuffer({
+ background: true,
+ nearing: limit,
+ offset: offset
+ });
+ }
+
+ return true;
+ },
+
+ // opts = (object) The following parameters:
+ // One of the following is REQUIRED:
+ // offset: (integer) Value of offset
+ // search: (object) List of search keys/values
+ //
+ // OPTIONAL:
+ // background: (boolean) Do fetch in background
+ // initial: (boolean) Is this the initial access to this view?
+ // nearing: (string) TODO [only used w/offset]
+ // params: (object) Parameters to add to outgoing URL
+ // view: (string) The view to retrieve. Defaults to current view.
+ _fetchBuffer: function(opts)
+ {
+ if (this.isbusy) {
+ return this._fetchBuffer.bind(this, opts).defer();
+ }
+
+ this.isbusy = true;
+
+ // Only call onFetch() if we are loading in foreground.
+ if (!opts.background && this.opts.onFetch) {
+ this.opts.onFetch();
+ }
+
+ var llist, lrows, rlist, tmp, type, value,
+ view = (opts.view || this.view),
+ b = this._getBuffer(view),
+ params = $H(opts.params),
+ r_id = this.request_num++;
+
+ params.update({ request_id: r_id });
+
+ // Determine if we are querying via offset or a search query
+ if (opts.search || opts.initial) {
+ /* If this is an initial request, 'type' will be set correctly
+ * further down in the code. */
+ if (opts.search) {
+ type = 'search';
+ value = opts.search;
+ params.set('search', Object.toJSON(value));
+ } else {
+ params.set('initial', 1);
+ }
+ tmp = this._lookbehind();
+
+ params.update({
+ search_after: this.bufferSize() - tmp,
+ search_before: tmp
+ });
+ }
+
+ if (!opts.search) {
+ type = 'rownum';
+ value = opts.offset + 1;
+
+ // llist: keys - request_ids; vals - loading rownums
+ llist = b.getMetaData('llist') || $H();
+ lrows = llist.values().flatten();
+
+ b.setMetaData({ req_offset: opts.offset }, true);
+
+ /* If the current offset is part of a pending request, update
+ * the offset. */
+ if (lrows.size() &&
+ !params.get('purge') &&
+ b.sliceLoaded(value, lrows)) {
+ /* One more hurdle. If we are loading in background, and now
+ * we are in foreground, we need to search for the request
+ * that contains the current rownum. For now, just use the
+ * last request. */
+ if (!this.active_req && !opts.background) {
+ this.active_req = llist.keys().numericSort().last();
+ }
+ this.isbusy = false;
+ return;
+ }
+
+ /* This gets the list of rows needed which do not already appear
+ * in the buffer. */
+ tmp = this._getSliceBounds(value, opts.nearing, view);
+ rlist = $A($R(tmp.start, tmp.end)).diff(b.getAllRows());
+
+ if (!params.get('purge') && !rlist.size()) {
+ this.isbusy = false;
+ return;
+ }
+
+ /* Add rows to the loading list for the view. */
+ rlist = rlist.diff(lrows).numericSort();
+ llist.set(r_id, rlist);
+ b.setMetaData({ llist: llist }, true);
+
+ params.update({ slice: rlist.first() + ':' + rlist.last() });
+ }
+
+ if (!opts.background) {
+ this.active_req = r_id;
+ this._handleWait();
+ }
+
+ this._ajaxRequest(params, { noslice: true, view: view });
+
+ this.isbusy = false;
+ },
+
+ // rownum = (integer) Row number
+ // nearing = (string) 'bottom', 'top', null
+ _getSliceBounds: function(rownum, nearing)
+ {
+ var b_size = this.bufferSize(),
+ ob = {};
+
+ switch (nearing) {
+ case 'bottom':
+ ob.start = rownum + this.getPageSize();
+ ob.end = ob.start + b_size;
+ break;
+
+ case 'top':
+ ob.start = Math.max(rownum - b_size, 1);
+ ob.end = rownum;
+ break;
+
+ default:
+ ob.start = Math.max(rownum - this._lookbehind(), 1);
+ ob.end = ob.start + b_size;
+ break;
+ }
+
+ return ob;
+ },
+
+ _lookbehind: function()
+ {
+ return parseInt(0.4 * this.bufferSize(), 10);
+ },
+
+ // args = (object) The list of parameters.
+ // opts = (object) [noslice, view]
+ // Returns a Hash object
+ addRequestParams: function(args, opts)
+ {
+ opts = opts || {};
+ var cid = this.getMetaData('cacheid', opts.view),
+ cached, params, rowlist;
+
+ params = this.opts.onAjaxRequest
+ ? this.opts.onAjaxRequest(opts.view || this.view)
+ : $H();
+
+ params.update({ view: opts.view || this.view });
+
+ if (cid) {
+ params.update({ cacheid: cid });
+ }
+
+ if (!opts.noslice) {
+ rowlist = this._getSliceBounds(this.currentOffset(), null, opts.view);
+ params.update({ slice: rowlist.start + ':' + rowlist.end });
+ }
+
+ if (this.opts.onCachedList) {
+ cached = this.opts.onCachedList(opts.view || this.view);
+ } else {
+ cached = this._getBuffer(opts.view).getAllUIDs();
+ cached = cached.size()
+ ? cached.toJSON()
+ : '';
+ }
+
+ if (cached.length) {
+ params.update({ cached: cached });
+ }
+
+ return params.merge(args);
+ },
+
+ // params - (object) A list of parameters to send to server
+ // opts - (object) Args to pass to addRequestParams().
+ _ajaxRequest: function(params, other)
+ {
+ new Ajax.Request(this.opts.ajax_url, Object.extend(this.opts.ajax_opts || {}, {
+ evalJS: false,
+ evalJSON: true,
+ onComplete: this.ajax_response,
+ parameters: this.addRequestParams(params, other)
+ }));
+ },
+
+ _ajaxRequestComplete: function(r)
+ {
+ if (r.responseJSON) {
+ this.parseJSONResponse(r.responseJSON);
+ }
+ },
+
+ // r - (object) responseJSON returned from the server.
+ parseJSONResponse: function(r)
+ {
+ if (!r.ViewPort) {
+ return;
+ }
+
+ r = r.ViewPort;
+
+ if (r.rangelist) {
+ this.select(this.createSelection('uid', r.rangelist, r.view));
+ if (this.opts.onEndFetch) {
+ this.opts.onEndFetch();
+ }
+ }
+
+ if (r.cacheid) {
+ this._ajaxResponse(r);
+ }
+ },
+
+ // r = (Object) viewport response object
+ _ajaxResponse: function(r)
+ {
+ if (this.isbusy) {
+ this._ajaxResponse.bind(this, r).defer();
+ return;
+ }
+
+ this.isbusy = true;
+ this._clearWait();
+
+ var offset,
+ buffer = this._getBuffer(r.view),
+ llist = buffer.getMetaData('llist') || $H();
+
+ buffer.update(Object.isArray(r.data) ? {} : r.data, Object.isArray(r.rowlist) ? {} : r.rowlist, r.metadata || {}, { reset: r.reset, resetmd: r.resetmd, update: r.update });
+
+ llist.unset(r.request_id);
+
+ buffer.setMetaData({
+ cacheid: r.cacheid,
+ label: r.label,
+ llist: llist,
+ total_rows: r.totalrows
+ }, true);
+
+ if (this.opts.onCacheUpdate) {
+ this.opts.onCacheUpdate(r.view);
+ }
+
+ if (r.request_id &&
+ r.request_id == this.active_req) {
+ this.active_req = null;
+ offset = buffer.getMetaData('req_offset');
+ buffer.setMetaData({ req_offset: undefined });
+
+ if (this.opts.onEndFetch) {
+ this.opts.onEndFetch();
+ }
+ }
+
+ // TODO: Flag for no _fetchBuffer()?
+ if (this.view == r.view) {
+ this._updateContent(Object.isUndefined(offset) ? (r.rownum ? Number(r.rownum) - 1 : this.currentOffset()) : offset);
+ }
+
+ this.isbusy = false;
+ },
+
+ // offset = (integer) TODO
+ // opts = (object) TODO [background, view]
+ _updateContent: function(offset, opts)
+ {
+ opts = opts || {};
+
+ if (!this._getBuffer(opts.view).sliceLoaded(offset)) {
+ opts.offset = offset;
+ this._fetchBuffer(opts);
+ return false;
+ }
+
+ var c = this.opts.content,
+ c_nodes = [],
+ page_size = this.getPageSize(),
+ rows;
+
+ if (this.opts.onClear) {
+ this.opts.onClear(this.visibleRows());
+ }
+
+ this.scroller.updateSize();
+ this.scrollTo(offset + 1, { noupdate: true, top: true });
+
+ offset = this.currentOffset();
+ rows = this.createSelection('rownum', $A($R(offset + 1, offset + page_size)));
+
+ if (rows.size()) {
+ c_nodes = rows.get('dataob');
+ c.update(c_nodes.collect(this.prepareRow.bind(this)).join(''));
+ } else {
+ c.update(this.empty_msg);
+ }
+
+ if (this.opts.onContentComplete) {
+ this.opts.onContentComplete(c_nodes);
+ }
+
+ return true;
+ },
+
+ prepareRow: function(row)
+ {
+ var r = Object.clone(row);
+
+ r.bg = r.bg
+ ? row.bg.clone()
+ : [];
+
+ if (this.getSelected().contains('uid', r.vp_id)) {
+ r.bg.push('vpRowSelected');
+ }
+
+ r.bg.unshift('vpRow');
+
+ if (this.opts.onContent) {
+ this.opts.onContent(r);
+ }
+
+ // Mandatory DOM ID and class information.
+ r.vpData = 'id="' + r.domid + '" class="' + r.bg.join(' ') + '"';
+
+ return this.template.evaluate(r);
+ },
+
+ updateRow: function(row)
+ {
+ var d = $(row.domid);
+ if (d) {
+ if (this.opts.onClear) {
+ this.opts.onClear([ d ]);
+ }
+
+ d.replace(this.prepareRow(row));
+
+ if (this.opts.onContentComplete) {
+ this.opts.onContentComplete([ row ]);
+ }
+ }
+
+ },
+
+ _handleWait: function(call)
+ {
+ this._clearWait();
+
+ // Server did not respond in defined amount of time. Alert the
+ // callback function and set the next timeout.
+ if (call && this.opts.onWait) {
+ this.opts.onWait();
+ }
+
+ // Call wait handler every x seconds
+ if (this.opts.viewport_wait) {
+ this.waitHandler = this._handleWait.bind(this, true).delay(this.opts.viewport_wait);
+ }
+ },
+
+ _clearWait: function()
+ {
+ if (this.waitHandler) {
+ clearTimeout(this.waitHandler);
+ this.waitHandler = null;
+ }
+ },
+
+ visibleRows: function()
+ {
+ return this.opts.content.childElements();
+ },
+
+ getMetaData: function(id, view)
+ {
+ return this._getBuffer(view).getMetaData(id);
+ },
+
+ setMetaData: function(vals, view)
+ {
+ this._getBuffer(view).setMetaData(vals, false);
+ },
+
+ _getBuffer: function(view, create)
+ {
+ view = view || this.view;
+
+ return (!create && this.views[view])
+ ? this.views[view]
+ : new ViewPort_Buffer(this, view);
+ },
+
+ currentOffset: function()
+ {
+ return this.scroller.currentOffset();
+ },
+
+ _getLineHeight: function()
+ {
+ if (!this.line_height) {
+ // To avoid hardcoding the line height, create a temporary row to
+ // figure out what the CSS says.
+ var d = new Element('DIV', { className: this.opts.content_class }).insert(new Element('DIV', { className: 'vpRow' })).hide();
+ $(document.body).insert(d);
+ this.line_height = d.getHeight();
+ d.remove();
+ }
+
+ return this.line_height;
+ },
+
+ // (type) = (string) [null (DEFAULT), 'current', 'default', 'max']
+ getPageSize: function(type)
+ {
+ switch (type) {
+ case 'current':
+ return Math.min(this.page_size, this.getMetaData('total_rows'));
+
+ case 'default':
+ return Math.max(parseInt(this.getPageSize('max') * 0.45), 5);
+
+ case 'max':
+ case 'splitmax':
+ return parseInt((this._getMaxHeight() - (type == 'max' ? 0 : 100)) / this._getLineHeight());
+
+ default:
+ return this.page_size;
+ }
+ },
+
+ _getMaxHeight: function()
+ {
+ return document.viewport.getHeight() - this.opts.content.viewportOffset()[1];
+ },
+
+ bufferSize: function()
+ {
+ // Buffer size must be at least the maximum page size.
+ return Math.round(Math.max(this.getPageSize('max') + 1, this.opts.buffer_pages * this.getPageSize()));
+ },
+
+ limitTolerance: function()
+ {
+ return Math.round(this.bufferSize() * (this.opts.limit_factor / 100));
+ },
+
+ showSplitPane: function(show)
+ {
+ this.show_split_pane = show;
+ this.onResize(true);
+ },
+
+ _initSplitBar: function()
+ {
+ if (this.split_bar) {
+ return;
+ }
+
+ this.split_bar = $(this.opts.split_bar);
+ new Drag(this.split_bar, {
+ constraint: 'vertical',
+ ghosting: true,
+ nodrop: true,
+ onStart: function() {
+ // Cache these values since we will be using them multiple
+ // times in snap().
+ this.sp = {
+ lh: this._getLineHeight(),
+ lines: this.page_size,
+ max: this.getPageSize('splitmax'),
+ orig: this.page_size,
+ pos: $(this.opts.content).positionedOffset()[1]
+ };
+ }.bind(this),
+ snap: function(x, y, elt) {
+ var l = parseInt((y - this.sp.pos) / this.sp.lh);
+ if (l < 1) {
+ l = 1;
+ } else if (l > this.sp.max) {
+ l = this.sp.max;
+ }
+ this.sp.lines = l;
+ return [ x, this.sp.pos + (l * this.sp.lh) ];
+ }.bind(this),
+ onEnd: function() {
+ this.page_size = this.sp.lines;
+ this.onResize(true);
+ if (this.opts.onSplitBarChange &&
+ this.sp.orig != this.sp.lines) {
+ this.opts.onSplitBarChange();
+ }
+ }.bind(this)
+ });
+ this.split_bar.observe('dblclick', function() {
+ var old_size = this.page_size;
+ this.page_size = this.getPageSize('default');
+ this._onResize(true);
+ if (this.opts.onSplitBarChange &&
+ old_size != this.page_size) {
+ this.opts.onSplitBarChange();
+ }
+ }.bind(this));
+ },
+
+ createSelection: function(format, data, view)
+ {
+ var buffer = this._getBuffer(view);
+ return buffer ? new ViewPort_Selection(buffer, format, data) : new ViewPort_Selection(this._getBuffer(this.view));
+ },
+
+ getSelection: function(view)
+ {
+ var buffer = this._getBuffer(view);
+ return this.createSelection('uid', buffer ? buffer.getAllUIDs() : [], view);
+ },
+
+ // vs = (Viewport_Selection | array) A Viewport_Selection object -or-, if
+ // opts.range is set, an array of row numbers.
+ // opts = (object) TODO [add, range]
+ select: function(vs, opts)
+ {
+ opts = opts || {};
+
+ var b = this._getBuffer(),
+ sel, slice;
+
+ if (opts.range) {
+ slice = this.createSelection('rownum', vs);
+ if (vs.size() != slice.size()) {
+ if (this.opts.onFetch) {
+ this.opts.onFetch();
+ }
+
+ this._ajaxRequest({ rangeslice: 1, slice: vs.min() + ':' + vs.size() });
+ return;
+ }
+ vs = slice;
+ }
+
+ if (!opts.add) {
+ sel = this.getSelected();
+ b.deselect(sel, true);
+ sel.get('div').invoke('removeClassName', 'vpRowSelected');
+ }
+ b.select(vs);
+ vs.get('div').invoke('addClassName', 'vpRowSelected');
+ if (this.opts.onSelect) {
+ this.opts.onSelect(vs, opts);
+ }
+ },
+
+ // vs = (Viewport_Selection) A Viewport_Selection object.
+ // opts = (object) TODO [clearall]
+ deselect: function(vs, opts)
+ {
+ opts = opts || {};
+
+ if (vs.size() &&
+ this._getBuffer().deselect(vs, opts && opts.clearall)) {
+ vs.get('div').invoke('removeClassName', 'vpRowSelected');
+ if (this.opts.onDeselect) {
+ this.opts.onDeselect(vs, opts)
+ }
+ }
+ },
+
+ getSelected: function()
+ {
+ return Object.clone(this._getBuffer().getSelected());
+ }
+
+}),
+
+/**
+ * ViewPort_Scroller
+ */
+ViewPort_Scroller = Class.create({
+ // Variables initialized to undefined: noupdate
+
+ initialize: function(vp)
+ {
+ this.vp = vp;
+ },
+
+ _createScrollBar: function()
+ {
+ if (this.scrollDiv) {
+ return false;
+ }
+
+ var c = this.vp.opts.content;
+
+ // Create the outer div.
+ this.scrollDiv = new Element('DIV', { className: 'sbdiv' }).setStyle({ height: c.getHeight() + 'px' }).hide();
+
+ // Add scrollbar to parent viewport and give our parent a right
+ // margin just big enough to accomodate the scrollbar.
+ c.insert({ after: this.scrollDiv }).setStyle({ marginRight: '-' + this.scrollDiv.getWidth() + 'px' });
+
+ // Create scrollbar object.
+ this.scrollbar = new DimpSlider(this.scrollDiv, {
+ buttonclass: { up: 'sbup', down: 'sbdown' },
+ cursorclass: 'sbcursor',
+ onChange: this._onScroll.bind(this),
+ onSlide: this.vp.opts.onSlide ? this.vp.opts.onSlide : null,
+ pagesize: this.vp.getPageSize(),
+ totalsize: this.vp.getMetaData('total_rows')
+ });
+
+ // Mouse wheel handler.
+ c.observe(Prototype.Browser.Gecko ? 'DOMMouseScroll' : 'mousewheel', function(e) {
+ var move_num = Math.min(this.vp.getPageSize(), 3);
+ this.moveScroll(this.currentOffset() + ((e.wheelDelta >= 0 || e.detail < 0) ? (-1 * move_num) : move_num));
+ }.bindAsEventListener(this));
+
+ return true;
+ },
+
+ onResize: function()
+ {
+ if (!this.scrollDiv) {
+ return;
+ }
+
+ // Update the container div.
+ this.scrollsize = this.vp.opts.content.getHeight();
+ this.scrollDiv.setStyle({ height: this.scrollsize + 'px' });
+
+ // Update the scrollbar size
+ this.updateSize();
+
+ // Update displayed content.
+ this.vp.requestContentRefresh(this.currentOffset());
+ },
+
+ updateSize: function()
+ {
+ if (!this._createScrollBar()) {
+ this.scrollbar.updateHandleLength(this.vp.getPageSize(), this.vp.getMetaData('total_rows'));
+ }
+ },
+
+ clear: function()
+ {
+ if (this.scrollDiv) {
+ this.scrollbar.updateHandleLength(0, 0);
+ }
+ },
+
+ // offset = (integer) Offset to move the scrollbar to
+ moveScroll: function(offset)
+ {
+ this._createScrollBar();
+ this.scrollbar.setScrollPosition(offset);
+ },
+
+ _onScroll: function()
+ {
+ if (!this.noupdate) {
+ this.vp.requestContentRefresh(this.currentOffset());
+ }
+ },
+
+ currentOffset: function()
+ {
+ return this.scrollbar ? this.scrollbar.getValue() : 0;
+ }
+
+}),
+
+/**
+ * ViewPort_Buffer
+ *
+ * Note: recognize the difference between offset (current location in the
+ * viewport - starts at 0) with start parameters (the row numbers - starts
+ * at 1).
+ */
+ViewPort_Buffer = Class.create({
+
+ initialize: function(vp, view)
+ {
+ this.vp = vp;
+ this.view = view;
+ this.clear();
+ },
+
+ getView: function()
+ {
+ return this.view;
+ },
+
+ // d = (object) Data
+ // l = (object) Rowlist
+ // md = (object) User defined metadata
+ // opts = (object) TODO [reset, resetmd, update]
+ update: function(d, l, md, opts)
+ {
+ var val;
+ d = $H(d);
+ l = $H(l);
+ opts = opts || {};
+
+ if (!opts.reset && this.data.size()) {
+ this.data.update(d);
+ } else {
+ this.data = d;
+ }
+
+ if (opts.update || opts.reset) {
+ this.uidlist = l;
+ this.rowlist = $H();
+ } else {
+ this.uidlist = this.uidlist.size() ? this.uidlist.merge(l) : l;
+ }
+
+ l.each(function(o) {
+ this.rowlist.set(o.value, o.key);
+ }, this);
+
+ if (opts.resetmd) {
+ this.usermdata = $H(md);
+ } else {
+ $H(md).each(function(pair) {
+ if (Object.isString(pair.value) || Object.isNumber(pair.value)) {
+ this.usermdata.set(pair.key, pair.value);
+ } else {
+ val = this.usermdata.get(pair.key);
+ if (val) {
+ this.usermdata.get(pair.key).update($H(pair.value));
+ } else {
+ this.usermdata.set(pair.key, $H(pair.value));
+ }
+ }
+ }, this);
+ }
+ },
+
+ // offset = (integer) Offset of the beginning of the slice.
+ // rows = (array) Additional rows to include in the search.
+ sliceLoaded: function(offset, rows)
+ {
+ var range = $A($R(offset + 1, Math.min(offset + this.vp.getPageSize() - 1, this.getMetaData('total_rows'))));
+
+ return rows
+ ? (range.diff(this.rowlist.keys().concat(rows)).size() == 0)
+ : !this._rangeCheck(range);
+ },
+
+ isNearingLimit: function(offset)
+ {
+ if (this.uidlist.size() != this.getMetaData('total_rows')) {
+ if (offset != 0 &&
+ this._rangeCheck($A($R(Math.max(offset + 1 - this.vp.limitTolerance(), 1), offset)))) {
+ return 'top';
+ } else if (this._rangeCheck($A($R(offset + 1, Math.min(offset + this.vp.limitTolerance() + this.vp.getPageSize() - 1, this.getMetaData('total_rows')))).reverse())) {
+ // Search for missing messages in reverse order since in
+ // normal usage (sequential scrolling through the message
+ // list) messages are more likely to be missing at furthest
+ // from the current view.
+ return 'bottom';
+ }
+ }
+
+ return false;
+ },
+
+ _rangeCheck: function(range)
+ {
+ return !range.all(this.rowlist.get.bind(this.rowlist));
+ },
+
+ getData: function(uids)
+ {
+ return uids.collect(function(u) {
+ var e = this.data.get(u);
+ if (!Object.isUndefined(e)) {
+ // We can directly write the rownum to the original object
+ // since we will always rewrite when creating rows.
+ e.domid = 'vp_row' + u;
+ e.rownum = this.uidlist.get(u);
+ e.vp_id = u;
+ return e;
+ }
+ }, this).compact();
+ },
+
+ getAllUIDs: function()
+ {
+ return this.uidlist.keys();
+ },
+
+ getAllRows: function()
+ {
+ return this.rowsToUIDs(this.rowlist.keys());
+ },
+
+ rowsToUIDs: function(rows)
+ {
+ return rows.collect(this.rowlist.get.bind(this.rowlist)).compact();
+ },
+
+ // vs = (Viewport_Selection) TODO
+ select: function(vs)
+ {
+ this.selected.add('uid', vs.get('uid'));
+ },
+
+ // vs = (Viewport_Selection) TODO
+ // clearall = (boolean) Clear all entries?
+ deselect: function(vs, clearall)
+ {
+ var size = this.selected.size();
+
+ if (clearall) {
+ this.selected.clear();
+ } else {
+ this.selected.remove('uid', vs.get('uid'));
+ }
+ return size != this.selected.size();
+ },
+
+ getSelected: function()
+ {
+ return this.selected;
+ },
+
+ // rownums = (array) Array of row numbers to remove.
+ remove: function(rownums)
+ {
+ var minrow = rownums.min(),
+ rowsize = this.rowlist.size(),
+ rowsubtract = 0,
+ newsize = rowsize - rownums.size();
+
+ return this.rowlist.keys().each(function(n) {
+ if (n >= minrow) {
+ var id = this.rowlist.get(n), r;
+ if (rownums.include(n)) {
+ this.data.unset(id);
+ this.uidlist.unset(id);
+ rowsubtract++;
+ } else if (rowsubtract) {
+ r = n - rowsubtract;
+ this.rowlist.set(r, id);
+ this.uidlist.set(id, r);
+ }
+ if (n > newsize) {
+ this.rowlist.unset(n);
+ }
+ }
+ }, this);
+ },
+
+ clear: function()
+ {
+ this.data = $H();
+ this.mdata = $H({ total_rows: 0 });
+ this.rowlist = $H();
+ this.selected = new ViewPort_Selection(this);
+ this.uidlist = $H();
+ this.usermdata = $H();
+ },
+
+ getMetaData: function(id)
+ {
+ return this.mdata.get(id) || this.usermdata.get(id);
+ },
+
+ setMetaData: function(vals, priv)
+ {
+ if (priv) {
+ this.mdata.update(vals);
+ } else {
+ this.usermdata.update(vals);
+ }
+ }
+
+}),
+
+/**
+ * ViewPort_Selection
+ */
+ViewPort_Selection = Class.create({
+
+ // Define property to aid in object detection
+ viewport_selection: true,
+
+ // Formats:
+ // 'dataob' = Data objects
+ // 'div' = DOM DIVs
+ // 'domid' = DOM IDs
+ // 'rownum' = Row numbers
+ // 'uid' = Unique IDs
+ initialize: function(buffer, format, data)
+ {
+ this.buffer = buffer;
+ this.clear();
+ if (!Object.isUndefined(format)) {
+ this.add(format, data);
+ }
+ },
+
+ add: function(format, d)
+ {
+ var c = this._convert(format, d);
+ this.data = this.data.size() ? this.data.concat(c).uniq() : c;
+ },
+
+ remove: function(format, d)
+ {
+ this.data = this.data.diff(this._convert(format, d));
+ },
+
+ _convert: function(format, d)
+ {
+ d = Object.isArray(d) ? d : [ d ];
+
+ switch (format) {
+ case 'dataob':
+ return d.pluck('vp_id');
+
+ case 'div':
+ return d.pluck('id').invoke('substring', 6);
+
+ case 'domid':
+ return d.invoke('substring', 6);
+
+ case 'rownum':
+ return this.buffer.rowsToUIDs(d);
+
+ case 'uid':
+ return d;
+ }
+ },
+
+ clear: function()
+ {
+ this.data = [];
+ },
+
+ get: function(format)
+ {
+ format = Object.isUndefined(format) ? 'uid' : format;
+ if (format == 'uid') {
+ return this.data;
+ }
+ var d = this.buffer.getData(this.data);
+
+ switch (format) {
+ case 'dataob':
+ return d;
+
+ case 'div':
+ return d.pluck('domid').collect(function(e) { return $(e); }).compact();
+
+ case 'domid':
+ return d.pluck('domid');
+
+ case 'rownum':
+ return d.pluck('rownum');
+ }
+ },
+
+ contains: function(format, d)
+ {
+ return this.data.include(this._convert(format, d).first());
+ },
+
+ // params = (Object) Key is search key, value is object -> key of object
+ // must be the following:
+ // equal - Matches any value contained in the query array.
+ // not - Matches any value not contained in the query array.
+ // regex - Matches the RegExp contained in the query.
+ search: function(params)
+ {
+ return new ViewPort_Selection(this.buffer, 'uid', this.get('dataob').findAll(function(i) {
+ // i = data object
+ return $H(params).all(function(k) {
+ // k.key = search key; k.value = search criteria
+ return $H(k.value).all(function(s) {
+ // s.key = search type; s.value = search query
+ switch (s.key) {
+ case 'equal':
+ case 'not':
+ var r = i[k.key] && s.value.include(i[k.key]);
+ return (s.key == 'equal') ? r : !r;
+
+ case 'regex':
+ return i[k.key].match(s.value);
+ }
+ });
+ });
+ }).pluck('vp_id'));
+ },
+
+ size: function()
+ {
+ return this.data.size();
+ },
+
+ set: function(vals)
+ {
+ this.get('dataob').each(function(d) {
+ $H(vals).each(function(v) {
+ d[v.key] = v.value;
+ });
+ });
+ },
+
+ getBuffer: function()
+ {
+ return this.buffer;
+ }
+
+});
+
+/** Utility Functions **/
+Object.extend(Array.prototype, {
+ // Need our own diff() function because prototypejs's without() function
+ // does not handle array input.
+ diff: function(values)
+ {
+ return this.select(function(value) {
+ return !values.include(value);
+ });
+ },
+ numericSort: function()
+ {
+ return this.collect(Number).sort(function(a, b) {
+ return (a > b) ? 1 : ((a < b) ? -1 : 0);
+ });
+ }
+});
--- /dev/null
+/**
+ * Provides the javascript for the acl.php script (standard view).
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var ImpAcl = {
+
+ acl_loading: false,
+
+ folderChange: function(e, clear)
+ {
+ if ($F('aclfolder')) {
+ if (!this.acl_loading || clear != null) {
+ this.acl_loading = true;
+ $('acl').disable();
+ $('folders').submit();
+ e.stop();
+ }
+ }
+ },
+
+ changeHandler: function(e)
+ {
+ switch (e.element().readAttribute('id')) {
+ case 'aclfolder':
+ this.folderChange(e);
+ break;
+ }
+ },
+
+ clickHandler: function(e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = e.element();
+
+ while (Object.isElement(elt)) {
+ switch (elt.readAttribute('id')) {
+ case 'changefolder':
+ case 'resetbut':
+ this.folderChange(e, true);
+ break;
+ }
+
+ elt = elt.up();
+ }
+ }
+
+};
+
+document.observe('change', ImpAcl.changeHandler.bindAsEventListener(ImpAcl));
+document.observe('click', ImpAcl.clickHandler.bindAsEventListener(ImpAcl));
--- /dev/null
+/**
+ * compose.js - Javascript code used in the DIMP compose view.
+ *
+ * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var DimpCompose = {
+ // Variables defaulting to empty/false:
+ // auto_save_interval, button_pressed, compose_cursor, dbtext,
+ // drafts_mbox, editor_on, mp_padding, resizebcc, resizecc, resizeto,
+ // row_height, sbtext, skip_spellcheck, spellcheck, uploading
+ last_msg: '',
+ textarea_ready: true,
+
+ confirmCancel: function()
+ {
+ if (window.confirm(DIMP.text_compose.cancel)) {
+ DimpCore.doAction(DIMP.conf_compose.auto_save_interval_val ? 'DeleteDraft' : 'CancelCompose', { imp_compose: $F('composeCache') });
+ this.updateDraftsMailbox();
+ return this.closeCompose();
+ }
+ },
+
+ updateDraftsMailbox: function()
+ {
+ if (DIMP.baseWindow.DimpBase &&
+ DIMP.baseWindow.DimpBase.folder == DIMP.conf_compose.drafts_mbox) {
+ DIMP.baseWindow.DimpBase.poll();
+ }
+ },
+
+ closeCompose: function()
+ {
+ if (DIMP.conf_compose.qreply) {
+ this.closeQReply();
+ } else if (DIMP.baseWindow.DimpBase || DIMP.conf_compose.popup) {
+ DimpCore.closePopup();
+ } else {
+ DimpCore.redirect(DIMP.conf.URI_DIMP);
+ }
+ },
+
+ closeQReply: function()
+ {
+ var al = $('attach_list').childElements();
+ this.last_msg = '';
+
+ if (al.size()) {
+ this.removeAttach(al);
+ }
+
+ $('composeCache').setValue('');
+ $('qreply', 'sendcc', 'sendbcc').invoke('hide');
+ [ $('msgData'), $('togglecc').up(), $('togglebcc').up() ].invoke('show');
+ if (this.editor_on) {
+ this.toggleHtmlEditor();
+ }
+ $('compose').reset();
+
+ // Disable auto-save-drafts now.
+ if (this.auto_save_interval) {
+ this.auto_save_interval.stop();
+ }
+ },
+
+ change_identity: function()
+ {
+ var lastSignature, msg, nextSignature, pos,
+ id = $F('identity'),
+ last = this.get_identity($F('last_identity')),
+ msgval = $('message'),
+ next = this.get_identity(id),
+ ssm = $('save_sent_mail');
+
+ $('sent_mail_folder_label').setText(next.id[5]);
+ $('bcc').setValue(next.id[6]);
+ if (ssm) {
+ ssm.writeAttribute('checked', next.id[4]);
+ }
+
+ // Finally try and replace the signature.
+ if (this.editor_on) {
+ msg = FCKeditorAPI.GetInstance('message').GetHTML().replace(/\r\n/g, '\n');
+ lastSignature = '<p><!--begin_signature--><!--end_signature--></p>';
+ nextSignature = '<p><!--begin_signature-->' + next.sig.replace(/^ ?<br \/>\n/, '').replace(/ +/g, ' ') + '<!--end_signature--></p>';
+
+ // Dot-all functionality achieved with [\s\S], see:
+ // http://simonwillison.net/2004/Sep/20/newlines/
+ msg = msg.replace(/<p>\s*<!--begin_signature-->[\s\S]*?<!--end_signature-->\s*<\/p>/, lastSignature);
+ } else {
+ msg = $F(msgval).replace(/\r\n/g, '\n');
+ lastSignature = last.sig;
+ nextSignature = next.sig;
+ }
+
+ pos = (last.id[2])
+ ? msg.indexOf(lastSignature)
+ : msg.lastIndexOf(lastSignature);
+
+ if (pos != -1) {
+ if (next.id[2] == last.id[2]) {
+ msg = msg.substring(0, pos) + nextSignature + msg.substring(pos + lastSignature.length, msg.length);
+ } else if (next.id[2]) {
+ msg = nextSignature + msg.substring(0, pos) + msg.substring(pos + lastSignature.length, msg.length);
+ } else {
+ msg = msg.substring(0, pos) + msg.substring(pos + lastSignature.length, msg.length) + nextSignature;
+ }
+
+ msg = msg.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');
+ if (this.editor_on) {
+ FCKeditorAPI.GetInstance('message').SetHTML(msg);
+ } else {
+ msgval.setValue(msg);
+ }
+ $('last_identity').setValue(id);
+ }
+ },
+
+ get_identity: function(id, editor_on)
+ {
+ editor_on = Object.isUndefined(editor_on) ? this.editor_on : editor_on;
+ return {
+ id: DIMP.conf_compose.identities[id],
+ sig: DIMP.conf_compose.identities[id][(editor_on ? 1 : 0)].replace(/^\n/, '')
+ };
+ },
+
+ uniqueSubmit: function(action)
+ {
+ var db, params, sb,
+ c = $('compose');
+
+ if (DIMP.SpellCheckerObject &&
+ DIMP.SpellCheckerObject.isActive()) {
+ DIMP.SpellCheckerObject.resume();
+ this.skip_spellcheck = true;
+ if (!this.textarea_ready) {
+ this.uniqueSubmit.bind(this, action).defer();
+ return;
+ }
+ }
+
+ if (action == 'send_message' || action == 'save_draft') {
+ this.button_pressed = true;
+
+ switch (action) {
+ case 'send_message':
+ if (($F('subject') == '') &&
+ !window.confirm(DIMP.text_compose.nosubject)) {
+ return;
+ }
+
+ if (!this.skip_spellcheck &&
+ DIMP.conf_compose.spellcheck &&
+ DIMP.SpellCheckerObject &&
+ !DIMP.SpellCheckerObject.isActive()) {
+ DIMP.SpellCheckerObject.spellCheck(this.onNoSpellError.bind(this, action));
+ return;
+ }
+
+ if (!this.sbtext) {
+ sb = $('send_button');
+ this.sbtext = sb.getText();
+ sb.setText(DIMP.text_compose.sending);
+ }
+ break;
+
+ case 'save_draft':
+ if (!this.dbtext) {
+ db = $('draft_button');
+ this.dbtext = db.getText();
+ db.setText(DIMP.text_compose.saving);
+ }
+ break;
+ }
+
+ // Don't send/save until uploading is completed.
+ if (this.uploading) {
+ (function() { if (this.button_pressed) { this.uniqueSubmit(action); } }).bind(this).delay(0.25);
+ return;
+ }
+ }
+
+ c.setStyle({ cursor: 'wait' });
+ this.skip_spellcheck = false;
+ $('action').setValue(action);
+
+ if (action == 'add_attachment') {
+ // We need a submit action here because browser security models
+ // won't let us access files on user's filesystem otherwise.
+ this.uploading = true;
+ c.submit();
+ } else {
+ // Move HTML text to textarea field for submission.
+ if (this.editor_on) {
+ FCKeditorAPI.GetInstance('message').UpdateLinkedField();
+ }
+
+ // Use an AJAX submit here so that we can do javascript-y stuff
+ // before having to close the window on success.
+ params = c.serialize(true);
+ if (!DIMP.baseWindow.DimpBase) {
+ params.nonotify = true;
+ }
+ DimpCore.doAction('*' + DIMP.conf.URI_COMPOSE, params, null, this.uniqueSubmitCallback.bind(this));
+ }
+ },
+
+ uniqueSubmitCallback: function(r)
+ {
+ var elt,
+ d = r.response;
+
+ if (!d) {
+ return;
+ }
+
+ if (d.imp_compose) {
+ $('composeCache').setValue(d.imp_compose);
+ }
+
+ if (d.success || d.action == 'add_attachment') {
+ switch (d.action) {
+ case 'auto_save_draft':
+ case 'save_draft':
+ this.button_pressed = false;
+
+ this.updateDraftsMailbox();
+
+ if (d.action == 'save_draft') {
+ if (DIMP.baseWindow.DimpBase && !DIMP.conf_compose.qreply) {
+ DIMP.baseWindow.DimpCore.showNotifications(r.msgs);
+ }
+ if (DIMP.conf_compose.close_draft) {
+ return this.closeCompose();
+ }
+ }
+ break;
+
+ case 'send_message':
+ this.button_pressed = false;
+ if (DIMP.baseWindow.DimpBase) {
+ if (d.reply_type) {
+ DIMP.baseWindow.DimpBase.flag(d.reply_type == 'reply' ? '\\answered' : '$forwarded', true, { index: d.index, mailbox: d.reply_folder, noserver: true });
+ }
+
+ // @TODO: Needed?
+ if (d.folder) {
+ DIMP.baseWindow.DimpBase.createFolder(d.folder);
+ }
+
+ if (d.draft_delete) {
+ DIMP.baseWindow.DimpBase.poll();
+ }
+
+ if (d.log) {
+ DIMP.baseWindow.DimpBase.updateMsgLog(d.log, { index: d.index, mailbox: d.reply_folder });
+ }
+
+ if (!DIMP.conf_compose.qreply) {
+ DIMP.baseWindow.DimpCore.showNotifications(r.msgs);
+ }
+ }
+ return this.closeCompose();
+
+ case 'add_attachment':
+ this.uploading = false;
+ if (d.success) {
+ this.addAttach(d.info.number, d.info.name, d.info.type, d.info.size);
+ } else {
+ this.button_pressed = false;
+ }
+ if (DIMP.conf_compose.attach_limit != -1 &&
+ $('attach_list').childElements().size() > DIMP.conf_compose.attach_limit) {
+ $('upload').writeAttribute('disabled', false);
+ elt = new Element('DIV', [ DIMP.text_compose.atc_limit ]);
+ } else {
+ elt = new Element('INPUT', { type: 'file', name: 'file_1' });
+ }
+ $('upload_wait').replace(elt.writeAttribute('id', 'upload'));
+ this.resizeMsgArea();
+ break;
+ }
+ } else {
+ this.button_pressed = false;
+ }
+
+ $('compose').setStyle({ cursor: null });
+
+ // Re-enable buttons if needed.
+ if (!this.button_pressed) {
+ if (this.sbtext) {
+ $('send_button').setText(this.sbtext);
+ }
+ if (this.dbtext) {
+ $('draft_button').setText(this.dbtext);
+ }
+ this.dbtext = this.sbtext = null;
+ }
+
+ if (!r.msgs_noauto) {
+ DimpCore.showNotifications(r.msgs);
+ }
+ },
+
+ onNoSpellError: function(action)
+ {
+ this.skip_spellcheck = true;
+ this.uniqueSubmit(action);
+ },
+
+ toggleHtmlEditor: function(noupdate)
+ {
+ if (!DIMP.conf_compose.rte_avail) {
+ return;
+ }
+ noupdate = noupdate || false;
+ if (DIMP.SpellCheckerObject) {
+ DIMP.SpellCheckerObject.resume();
+ }
+
+ var text;
+
+ if (this.editor_on) {
+ this.editor_on = false;
+
+ text = FCKeditorAPI.GetInstance('message').GetHTML();
+ $('messageParent').childElements().invoke('hide');
+ $('message').show();
+
+ DimpCore.doAction('Html2Text', { text: text }, null, this.setMessageText.bind(this), { asynchronous: false });
+ } else {
+ this.editor_on = true;
+ if (!noupdate) {
+ DimpCore.doAction('Text2Html', { text: $F('message') }, null, this.setMessageText.bind(this), { asynchronous: false });
+ }
+
+ oFCKeditor.Height = this.getMsgAreaHeight();
+ // Try to reuse the old fckeditor instance.
+ try {
+ FCKeditorAPI.GetInstance('message').SetHTML($F('message'));
+ $('messageParent').childElements().invoke('show');
+ $('message').hide();
+ } catch (e) {
+ this.RTELoading('show');
+ FCKeditor_OnComplete = this.RTELoading.curry('hide');
+ oFCKeditor.ReplaceTextarea();
+ }
+ }
+ $('htmlcheckbox').checked = this.editor_on;
+ $('html').setValue(this.editor_on ? 1 : 0);
+ },
+
+ RTELoading: function(cmd)
+ {
+ var o, r;
+ if (!$('rteloading')) {
+ r = new Element('DIV', { id: 'rteloading' }).clonePosition($('messageParent'));
+ $(document.body).insert(r);
+ o = r.viewportOffset();
+ $(document.body).insert(new Element('SPAN', { id: 'rteloadingtxt' }).setStyle({ top: (o.top + 15) + 'px', left: (o.left + 15) + 'px' }).insert(DIMP.text.loading));
+ }
+ $('rteloading', 'rteloadingtxt').invoke(cmd);
+ },
+
+ toggleHtmlCheckbox: function()
+ {
+ if (!this.editor_on || window.confirm(DIMP.text_compose.toggle_html)) {
+ this.toggleHtmlEditor();
+ }
+ },
+
+ getMsgAreaHeight: function()
+ {
+ return document.viewport.getHeight() - $('messageParent').cumulativeOffset()[1] - this.mp_padding;
+ },
+
+ initializeSpellChecker: function()
+ {
+ if (!DIMP.conf_compose.rte_avail) {
+ return;
+ }
+
+ if (typeof DIMP.SpellCheckerObject != 'object') {
+ // If we fired before the onload that initializes the spellcheck,
+ // wait.
+ this.initializeSpellChecker.bind(this).defer();
+ return;
+ }
+
+ DIMP.SpellCheckerObject.onBeforeSpellCheck = function() {
+ if (!this.editor_on) {
+ return;
+ }
+ DIMP.SpellCheckerObject.htmlAreaParent = 'messageParent';
+ DIMP.SpellCheckerObject.htmlArea = $('message').adjacent('iframe[id*=message]').first();
+ $('message').setValue(FCKeditorAPI.GetInstance('message').GetHTML());
+ this.textarea_ready = false;
+ }.bind(this);
+ DIMP.SpellCheckerObject.onAfterSpellCheck = function() {
+ if (!this.editor_on) {
+ return;
+ }
+ DIMP.SpellCheckerObject.htmlArea = DIMP.SpellCheckerObject.htmlAreaParent = null;
+ var ed = FCKeditorAPI.GetInstance('message');
+ ed.SetHTML($F('message'));
+ ed.Events.AttachEvent('OnAfterSetHTML', function() { this.textarea_ready = true; }.bind(this));
+ }.bind(this);
+ },
+
+ setMessageText: function(r)
+ {
+ var ta = $('message');
+ if (!ta) {
+ $('messageParent').insert(new Element('TEXTAREA', { id: 'message', name: 'message', style: 'width:100%;' }).insert(r.response.text));
+ } else {
+ ta.setValue(r.response.text);
+ }
+
+ if (!this.editor_on) {
+ this.resizeMsgArea();
+ }
+ },
+
+ fillForm: function(msg, header, focus, noupdate)
+ {
+ // On IE, this can get loaded before DOM;loaded. Check for an init
+ // value and don't load until it is available.
+ if (!this.resizeto) {
+ this.fillForm.bind(this, msg, header, focus, noupdate).defer();
+ return;
+ }
+
+ var bcc_add, fo,
+ identity = this.get_identity($F('last_identity')),
+ msgval = $('message');
+
+ if (!this.last_msg.empty() &&
+ this.last_msg != $F(msgval).replace(/\r/g, '') &&
+ !window.confirm(DIMP.text_compose.fillform)) {
+ return;
+ }
+
+ // Set auto-save-drafts now if not already active.
+ if (DIMP.conf_compose.auto_save_interval_val &&
+ !this.auto_save_interval) {
+ this.auto_save_interval = new PeriodicalExecuter(function() {
+ var cur_msg = this.editor_on
+ ? FCKeditorAPI.GetInstance('message').GetHTML()
+ : $F(msgval);
+ cur_msg = cur_msg.replace(/\r/g, '');
+ if (!cur_msg.empty() && this.last_msg != cur_msg) {
+ this.uniqueSubmit('auto_save_draft');
+ this.last_msg = cur_msg;
+ }
+ }.bind(this), DIMP.conf_compose.auto_save_interval_val * 60);
+ }
+
+ if (this.editor_on) {
+ fo = FCKeditorAPI.GetInstance('message');
+ fo.SetHTML(msg);
+ this.last_msg = fo.GetHTML().replace(/\r/g, '');
+ } else {
+ msgval.setValue(msg);
+ this.setCursorPosition(msgval);
+ this.last_msg = $F(msgval).replace(/\r/g, '');
+ }
+
+ $('to').setValue(header.to);
+ this.resizeto.resizeNeeded();
+ if (header.cc) {
+ $('cc').setValue(header.cc);
+ this.resizecc.resizeNeeded();
+ }
+ if (DIMP.conf_compose.cc) {
+ this.toggleCC('cc');
+ }
+ if (header.bcc) {
+ $('bcc').setValue(header.bcc);
+ this.resizebcc.resizeNeeded();
+ }
+ if (identity.id[6]) {
+ bcc_add = $F('bcc');
+ if (bcc_add) {
+ bcc_add += ', ';
+ }
+ $('bcc').setValue(bcc_add + identity.id[6]);
+ }
+ if (DIMP.conf_compose.bcc) {
+ this.toggleCC('bcc');
+ }
+ $('subject').setValue(header.subject);
+
+ Field.focus(focus || 'to');
+ this.resizeMsgArea();
+
+ if (DIMP.conf_compose.show_editor) {
+ if (!this.editor_on) {
+ this.toggleHtmlEditor(noupdate || false);
+ }
+ if (focus == 'message') {
+ this.focusEditor();
+ }
+ }
+ },
+
+ focusEditor: function()
+ {
+ try {
+ FCKeditorAPI.GetInstance('message').Focus();
+ } catch (e) {
+ this.focusEditor.bind(this).defer();
+ }
+ },
+
+ addAttach: function(atc_num, name, type, size)
+ {
+ var span = new Element('SPAN').insert(name),
+ div = new Element('DIV').insert(span).insert(' [' + type + '] (' + size + ' KB) '),
+ input = new Element('SPAN', { atc_id: atc_num, className: 'remove' }).insert(DIMP.text_compose.remove);
+ div.insert(input);
+ $('attach_list').insert(div);
+
+ if (type != 'application/octet-stream') {
+ span.addClassName('attachName');
+ }
+
+ this.resizeMsgArea();
+ },
+
+ removeAttach: function(e)
+ {
+ var ids = [];
+ e.each(function(n) {
+ n = $(n);
+ ids.push(n.down('SPAN.remove').readAttribute('atc_id'));
+ n.remove();
+ });
+ DimpCore.doAction('DeleteAttach', { atc_indices: ids, imp_compose: $F('composeCache') });
+ this.resizeMsgArea();
+ },
+
+ resizeMsgArea: function()
+ {
+ var m, rows,
+ de = document.documentElement,
+ msg = $('message');
+
+ if (!document.loaded) {
+ this.resizeMsgArea.bind(this).defer();
+ return;
+ }
+
+ if (this.editor_on) {
+ m = $('messageParent').select('iframe').last();
+ if (m) {
+ m.setStyle({ height: this.getMsgAreaHeight() + 'px' });
+ } else {
+ this.resizeMsgArea.bind(this).defer();
+ }
+ return;
+ }
+
+ this.mp_padding = $('messageParent').getHeight() - msg.getHeight();
+
+ if (!this.row_height) {
+ // Change the ID and name to not conflict with msg node.
+ m = $(msg.cloneNode(false)).writeAttribute({ id: null, name: null }).setStyle({ visibility: 'hidden' });
+ $(document.body).insert(m);
+ m.writeAttribute('rows', 1);
+ this.row_height = m.getHeight();
+ m.writeAttribute('rows', 2);
+ this.row_height = m.getHeight() - this.row_height;
+ m.remove();
+ }
+
+ /* Logic: Determine the size of a given textarea row, divide that size
+ * by the available height, round down to the lowest integer row, and
+ * resize the textarea. */
+ rows = parseInt(this.getMsgAreaHeight() / this.row_height);
+ msg.writeAttribute({ rows: rows, disabled: false });
+ if (de.scrollHeight - de.clientHeight) {
+ msg.writeAttribute({ rows: rows - 1 });
+ }
+
+ $('composeloading').hide();
+ },
+
+ uploadAttachment: function()
+ {
+ var u = $('upload');
+ this.uniqueSubmit('add_attachment');
+ u.replace(new Element('DIV', { id: 'upload_wait' }).insert(DIMP.text_compose.uploading + ' ' + $F(u)));
+ },
+
+ attachmentComplete: function()
+ {
+ var sf = $('submit_frame'),
+ doc = sf.contentDocument || sf.contentWindow.document;
+ DimpCore.doActionComplete({ responseJSON: doc.body.innerHTML.evalJSON(true) }, this.uniqueSubmitCallback.bind(this));
+ },
+
+ toggleCC: function(type)
+ {
+ $('send' + type).show();
+ $('toggle' + type).up().hide();
+ },
+
+ /* Sets the cursor to the given position. */
+ setCursorPosition: function(input)
+ {
+ var pos, range;
+
+ switch (DIMP.conf_compose.compose_cursor) {
+ case 'top':
+ pos = 0;
+ $('message').setValue('\n' + $F('message'));
+ break;
+
+ case 'bottom':
+ pos = $F('message').length;
+ break;
+
+ case 'sig':
+ pos = $F('message').replace(/\r\n/g, '\n').lastIndexOf(this.get_identity($F('last_identity')).sig) - 1;
+ break;
+
+ default:
+ return;
+ }
+
+ if (input.setSelectionRange) {
+ /* This works in Mozilla */
+ Field.focus(input);
+ input.setSelectionRange(pos, pos);
+ } else if (input.createTextRange) {
+ /* This works in IE */
+ range = input.createTextRange();
+ range.collapse(true);
+ range.moveStart('character', pos);
+ range.moveEnd('character', 0);
+ Field.select(range);
+ range.scrollIntoView(true);
+ }
+ },
+
+ /* Open the addressbook window. */
+ openAddressbook: function()
+ {
+ window.open(DIMP.conf_compose.URI_ABOOK, 'contacts', 'toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes,width=550,height=300,left=100,top=100');
+ },
+
+ /* Click observe handler. */
+ clickHandler: function(parentfunc, e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = orig = e.element(),
+ atc_num, id;
+
+ while (Object.isElement(elt)) {
+ id = elt.readAttribute('id');
+
+ switch (id) {
+ case 'togglebcc':
+ case 'togglecc':
+ this.toggleCC(id.substring(6));
+ this.resizeMsgArea();
+ break;
+
+ case 'compose_close':
+ this.confirmCancel();
+ break;
+
+ case 'draft_button':
+ case 'send_button':
+ this.uniqueSubmit(id == 'send_button' ? 'send_message' : 'save_draft');
+ break;
+
+ case 'htmlcheckbox':
+ this.toggleHtmlCheckbox();
+ break;
+
+ case 'sendcc':
+ case 'sendbcc':
+ case 'sendto':
+ if (orig.match('TD.label SPAN')) {
+ this.openAddressbook();
+ }
+ break;
+
+ case 'attach_list':
+ if (orig.match('SPAN.remove')) {
+ this.removeAttach([ orig.up() ]);
+ } else if (orig.match('SPAN.attachName')) {
+ atc_num = orig.next().readAttribute('atc_id');
+ DimpCore.popupWindow(DimpCore.addURLParam(DIMP.conf.URI_VIEW, { composeCache: $F('composeCache'), actionID: 'compose_attach_preview', id: atc_num }), $F('composeCache') + '|' + atc_num);
+ }
+ break;
+ }
+
+ elt = elt.up();
+ }
+
+ parentfunc(e);
+ },
+
+ changeHandler: function(e)
+ {
+ var elt = e.element(),
+ id = elt.readAttribute('id');
+
+ switch (id) {
+ case 'identity':
+ this.change_identity();
+ break;
+
+ case 'upload':
+ this.uploadAttachment();
+ break;
+ }
+ },
+
+ onDomLoad: function()
+ {
+ var boundResize = this.resizeMsgArea.bind(this);
+
+ DimpCore.growler_log = false;
+ DimpCore.init();
+
+ /* Attach event handlers. */
+ document.observe('change', this.changeHandler.bindAsEventListener(this));
+ Event.observe(window, 'resize', this.resizeMsgArea.bind(this));
+ $('compose').observe('submit', Event.stop);
+ $('submit_frame').observe('load', this.attachmentComplete.bind(this));
+
+ this.resizeMsgArea();
+ this.initializeSpellChecker();
+
+ // Automatically resize address fields.
+ this.resizeto = new ResizeTextArea('to', boundResize);
+ this.resizecc = new ResizeTextArea('cc', boundResize);
+ this.resizebcc = new ResizeTextArea('bcc', boundResize);
+
+ // Safari requires a submit target iframe to be at least 1x1 size or
+ // else it will open content in a new window. See:
+ // http://blog.caboo.se/articles/2007/4/2/ajax-file-upload
+ if (Prototype.Browser.WebKit) {
+ $('submit_frame').writeAttribute({ position: 'absolute', width: '1px', height: '1px' }).setStyle({ left: '-999px' }).show();
+ }
+
+ /* Add addressbook link formatting. */
+ if (DIMP.conf_compose.URI_ABOOK) {
+ $('sendto', 'sendcc', 'sendbcc').each(function(a) {
+ a.down('TD.label SPAN').addClassName('composeAddrbook');
+ });
+ }
+ }
+
+},
+
+ResizeTextArea = Class.create({
+ // Variables defaulting to empty:
+ // defaultRows, field, onResize
+ maxRows: 5,
+
+ initialize: function(field, onResize)
+ {
+ this.field = $(field);
+
+ this.defaultRows = Math.max(this.field.readAttribute('rows'), 1);
+ this.onResize = onResize;
+
+ var func = this.resizeNeeded.bindAsEventListener(this);
+ this.field.observe('mousedown', func).observe('keyup', func);
+
+ this.resizeNeeded();
+ },
+
+ resizeNeeded: function()
+ {
+ var lines = $F(this.field).split('\n'),
+ cols = this.field.readAttribute('cols'),
+ newRows = lines.size(),
+ oldRows = this.field.readAttribute('rows');
+
+ lines.each(function(line) {
+ if (line.length >= cols) {
+ newRows += Math.floor(line.length / cols);
+ }
+ });
+
+ if (newRows != oldRows) {
+ this.field.writeAttribute('rows', (newRows > oldRows) ? Math.min(newRows, this.maxRows) : Math.max(this.defaultRows, newRows));
+
+ if (this.onResize) {
+ this.onResize();
+ }
+ }
+ }
+
+});
+
+/* Attach event handlers. */
+document.observe('dom:loaded', DimpCompose.onDomLoad.bind(DimpCompose));
+
+/* Click handler. */
+DimpCore.clickHandler = DimpCore.clickHandler.wrap(DimpCompose.clickHandler.bind(DimpCompose));
--- /dev/null
+/**
+ * Provides the javascript for the compose.php script (standard view).
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var ImpCompose = {
+ /* Variables defined in compose.php:
+ * cancel_url, spellcheck, cursor_pos, identities, max_attachments,
+ * popup, redirect, reloaded, rtemode, smf_check, skip_spellcheck */
+ display_unload_warning: true,
+ textarea_ready: true,
+
+ confirmCancel: function(e)
+ {
+ if (window.confirm(IMP.text.compose_cancel)) {
+ this.display_unload_warning = false;
+ if (this.popup) {
+ if (this.cancel_url) {
+ self.location = this.cancel_url;
+ } else {
+ self.close();
+ }
+ } else {
+ window.location = this.cancel_url;
+ }
+ } else {
+ e.stop();
+ }
+ },
+
+ /**
+ * Sets the cursor to the given position.
+ */
+ setCursorPosition: function(input, position)
+ {
+ if (input.setSelectionRange) {
+ /* This works in Mozilla */
+ Field.focus(input);
+ input.setSelectionRange(position, position);
+ } else if (input.createTextRange) {
+ /* This works in IE */
+ var range = input.createTextRange();
+ range.collapse(true);
+ range.moveStart('character', position);
+ range.moveEnd('character', 0);
+ Field.select(range);
+ range.scrollIntoView(true);
+ }
+ },
+
+ changeIdentity: function(elt)
+ {
+ var id = $F(elt),
+ last = this.identities[$F('last_identity')],
+ next = this.identities[id],
+ i = 0,
+ bcc = $('bcc'),
+ save = $('ssm'),
+ smf = $('sent_mail_folder'),
+ ed, lastSignature, msg, nextSignature, pos, re;
+
+ // If the rich text editor is on, we'll use a regexp to find the
+ // signature comment and replace its contents.
+ if (this.rtemode) {
+ ed = FCKeditorAPI.GetInstance('message');
+
+ msg = ed.GetHTML.replace(/\r\n/g, '\n');
+
+ lastSignature = '<p><!--begin_signature--><!--end_signature--></p>';
+ nextSignature = '<p><!--begin_signature-->' + next[0].replace(/^ ?<br \/>\n/, '').replace(/ +/g, ' ') + '<!--end_signature--></p>';
+
+ // Dot-all functionality achieved with [\s\S], see:
+ // http://simonwillison.net/2004/Sep/20/newlines/
+ msg = msg.replace(/<p class="imp-signature">\s*<!--begin_signature-->[\s\S]*?<!--end_signature-->\s*<\/p>/, lastSignature);
+ } else {
+ msg = $F('message').replace(/\r\n/g, '\n');
+
+ lastSignature = last[0].replace(/^\n/, '');
+ nextSignature = next[0].replace(/^\n/, '');
+ }
+
+ pos = (last[1]) ? msg.indexOf(lastSignature) : msg.lastIndexOf(lastSignature);
+ if (pos != -1) {
+ if (next[1] == last[1]) {
+ msg = msg.substring(0, pos) + nextSignature + msg.substring(pos + lastSignature.length, msg.length);
+ } else if (next[1]) {
+ msg = nextSignature + msg.substring(0, pos) + msg.substring(pos + lastSignature.length, msg.length);
+ } else {
+ msg = msg.substring(0, pos) + msg.substring(pos + lastSignature.length, msg.length) + nextSignature;
+ }
+
+ msg = msg.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');
+
+ $('last_identity').setValue(id);
+ window.status = IMP.text.compose_sigreplace;
+ } else {
+ window.status = IMP.text.compose_signotreplace;
+ }
+
+ if (this.rtemode) {
+ ed.SetHTML(msg);
+ } else {
+ $('message').setValue(msg);
+ }
+
+
+ if (this.smf_check) {
+ $A(smf.options).detect(function(f) {
+ if (f.value == next[2]) {
+ smf.selectedIndex = i;
+ return true;
+ }
+ ++i;
+ });
+ } else {
+ if (smf.firstChild) {
+ smf.replaceChild(document.createTextNode(next[2]), smf.firstChild);
+ } else {
+ smf.appendChild(document.createTextNode(next[2]));
+ }
+ }
+
+ if (save) {
+ save.checked = next[3];
+ }
+ if (bcc) {
+ bccval = bcc.value;
+
+ if (last[4]) {
+ re = new RegExp(last[4] + ",? ?", 'gi');
+ bccval = bccval.replace(re, "");
+ if (bccval) {
+ bccval = bccval.replace(/, ?$/, "");
+ }
+ }
+
+ if (next[4]) {
+ if (bccval) {
+ bccval += ', ';
+ }
+ bccval += next[4];
+ }
+
+ bcc.setValue(bccval);
+ }
+ },
+
+ uniqSubmit: function(actionID, e)
+ {
+ var form;
+
+ if (!Object.isUndefined(e)) {
+ e.stop();
+ }
+
+ switch (actionID) {
+ case 'redirect':
+ if ($F('to') == '') {
+ alert(IMP.text.compose_recipient);
+ $('to').focus();
+ return;
+ }
+
+ form = $('redirect');
+ break;
+
+ case 'send_message':
+ if (($F('subject') == '') &&
+ !window.confirm(IMP.text.compose_nosubject)) {
+ return;
+ }
+
+ if (!this.skip_spellcheck &&
+ this.spellcheck &&
+ IMP.SpellCheckerObject &&
+ !IMP.SpellCheckerObject.isActive()) {
+ IMP.SpellCheckerObject.spellCheck(this.onNoSpellError.bind(this, actionID, e));
+ return;
+ }
+
+ this.skip_spellcheck = false;
+
+ if (IMP.SpellCheckerObject) {
+ IMP.SpellCheckerObject.resume();
+ }
+
+ // fall through
+
+ case 'add_attachment':
+ case 'save_draft':
+ form = $('compose');
+ $('actionID').setValue(actionID);
+ break;
+
+ case 'toggle_editor':
+ form = $('compose');
+ break;
+
+ default:
+ return;
+ }
+
+ // Ticket #6727; this breaks on WebKit w/FCKeditor.
+ if (!Prototype.Browser.WebKit) {
+ form.setStyle({ cursor: 'wait' });
+ }
+
+ this.display_unload_warning = false;
+ this._uniqSubmit(form);
+ },
+
+ _uniqSubmit: function(form)
+ {
+ if (this.textarea_ready) {
+ form.submit();
+ } else {
+ this._uniqSubmit.bind(this, form).defer();
+ }
+ },
+
+ onNoSpellError: function(actionID, e)
+ {
+ this.skip_spellcheck = true;
+ this.uniqSubmit(actionID, e);
+ },
+
+ attachmentChanged: function()
+ {
+ var fields = [],
+ usedFields = 0,
+ lastRow, newRow, td;
+
+ $('upload_atc').select('input[type="file"]').each(function(i) {
+ fields[fields.length] = i;
+ });
+
+ if (this.max_attachments !== null &&
+ fields.length == this.max_attachments) {
+ return;
+ }
+
+ fields.each(function(i) {
+ if (i.value.length > 0) {
+ usedFields++;
+ }
+ });
+
+ if (usedFields == fields.length) {
+ lastRow = $('attachment_row_' + usedFields);
+ if (lastRow) {
+ td = new Element('TD', { align: 'left' }).insert(new Element('STRONG').insert(IMP.text.compose_file + ' ' + (usedFields + 1) + ':')).insert(' ')
+
+ td.insert(new Element('INPUT', { type: 'file', id: 'upload_' + (usedFields + 1), name: 'upload_' + (usedFields + 1), size: 25 }));
+
+ newRow = new Element('TR', { id: 'attachment_row_' + (usedFields + 1) }).insert(td);
+
+ lastRow.parentNode.insertBefore(newRow, lastRow.nextSibling);
+ }
+ }
+ },
+
+ initializeSpellChecker: function()
+ {
+ if (typeof IMP.SpellCheckerObject != 'object') {
+ // If we fired before the onload that initializes the spellcheck,
+ // wait.
+ this.initializeSpellChecker.bind(this).defer();
+ return;
+ }
+
+ IMP.SpellCheckerObject.onBeforeSpellCheck = this._beforeSpellCheck.bind(this);
+ IMP.SpellCheckerObject.onAfterSpellCheck = this._afterSpellCheck.bind(this);
+ },
+
+ _beforeSpellCheck: function()
+ {
+ IMP.SpellCheckerObject.htmlAreaParent = 'messageParent';
+ IMP.SpellCheckerObject.htmlArea = $('message').adjacent('iframe[id*=message]').first();
+ $('message').setValue(FCKeditorAPI.GetInstance('message').GetHTML());
+ this.textarea_ready = false;
+ },
+
+ _afterSpellCheck: function()
+ {
+ IMP.SpellCheckerObject.htmlArea = IMP.SpellCheckerObject.htmlAreaParent = null;
+ var ed = FCKeditorAPI.GetInstance('message');
+ ed.SetHTML($('message').value);
+ ed.Events.AttachEvent('OnAfterSetHTML', this._afterSetHTML.bind(this));
+ },
+
+ _afterSetHTML: function()
+ {
+ this.textarea_ready = true;
+ },
+
+ clickHandler: function(e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = e.element(), name;
+
+ while (Object.isElement(elt)) {
+ if (elt.hasClassName('button')) {
+ name = elt.readAttribute('name');
+ switch (name) {
+ case 'btn_add_attachment':
+ case 'btn_redirect':
+ case 'btn_save_draft':
+ case 'btn_send_message':
+ this.uniqSubmit(name.substring(4), e);
+ break;
+
+ case 'btn_cancel_compose':
+ this.confirmCancel(e);
+ break;
+ }
+ }
+
+ elt = elt.up();
+ }
+ },
+
+ changeHandler: function(e)
+ {
+ var elt = e.element(),
+ id = elt.identify();
+
+ switch (id) {
+ case 'identity':
+ this.changeIdentity(elt);
+ break;
+
+ case 'stationery':
+ this.uniqSubmit('change_stationery', e);
+ break;
+
+ case 'sent_mail_folder':
+ $('ssm').writeAttribute('checked', 'checked');
+ break;
+
+ default:
+ if (id.substring(0, 7) == 'upload_') {
+ this.attachmentChanged();
+ }
+ break;
+ }
+ },
+
+ onDomLoad: function()
+ {
+ /* Prevent Return from sending messages - it should bring us out of
+ * autocomplete, not submit the whole form. */
+ $$('INPUT').each(function(i) {
+ /* Attach to everything but button and submit elements. */
+ if (i.type != 'submit' && i.type != 'button') {
+ i.observe('keydown', function(e) {
+ if (e.keyCode == 10 || e.keyCode == Event.KEY_RETURN) {
+ e.stop();
+ return false;
+ }
+ });
+ }
+ });
+
+ if (this.cursor_pos !== null && $('message')) {
+ this.setCursorPosition($('message'), this.cursor_pos);
+ }
+
+ if (this.redirect) {
+ $('to').focus();
+ } else {
+ if (Prototype.Browser.IE) {
+ $('subject').observe('keydown', function(e) {
+ if (e.keyCode == Event.KEY_TAB && !e.shiftKey) {
+ e.stop();
+ $('message').focus();
+ }
+ });
+ }
+
+ if (this.rtemode) {
+ this.initializeSpellChecker();
+ }
+
+ if ($('to') && !$F('to')) {
+ $('to').focus();
+ } else if (!$F('subject')) {
+ if (this.rtemode) {
+ $('subject').focus();
+ } else {
+ $('message').focus();
+ }
+ }
+ }
+ },
+
+ onLoad: function()
+ {
+ var d, e = this.redirect ? $('redirect') : $('compose');
+
+ if (this.popup && !this.reloaded) {
+ d = Math.min(e.getHeight(), screen.height - 100) - document.viewport.getHeight();
+ if (d > 0) {
+ window.resizeBy(0, d);
+ }
+ }
+
+ document.observe('click', this.clickHandler.bindAsEventListener(this));
+ document.observe('change', this.changeHandler.bindAsEventListener(this));
+ },
+
+ onBeforeUnload: function()
+ {
+ if (this.display_unload_warning) {
+ return IMP.text.compose_discard;
+ }
+ }
+
+};
+
+/* Code to run on window load. */
+document.observe('dom:loaded', ImpCompose.onDomLoad.bind(ImpCompose));
+Event.observe(window, 'load', ImpCompose.onLoad.bind(ImpCompose));
+
+/* Warn before closing the window. */
+Event.observe(window, 'beforeunload', ImpCompose.onBeforeUnload.bind(ImpCompose));
--- /dev/null
+/**
+ * Provides the javascript for the contacts.php script (standard view).
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var ImpContacts = {
+ // The following variables are defined in contacts.php:
+ // formname, to_only
+
+ _passAddresses: function()
+ {
+ var sa = '';
+
+ $('selected_addresses').childElements().each(function(s) {
+ if (s.value) {
+ sa += s.value + '|';
+ }
+ });
+
+ $('sa').setValue(sa);
+ },
+
+ sameOption: function(f, item, itemj)
+ {
+ var t = f + ": " + item.value,
+ tj = itemj.value;
+
+ return Try.these(
+ function() {
+ return (t == tj) || (decodeURIComponent(t) == decodeURIComponent(tj));
+ },
+ // Catch exception with NS 7.1
+ function() {
+ return (t == tj);
+ }
+ );
+ },
+
+ addAddress: function(f)
+ {
+ var d, l, option, s = $('search_results');
+
+ if (!$F(s).size()) {
+ alert(IMP.text.contacts_select);
+ } else {
+ d = $('selected_addresses');
+ l = $A(d).size();
+ s.childElements().each(function(i) {
+ if (i.value && i.selected) {
+ if (!$A(d).any(function(j) {
+ return this.sameOption(f, i, j);
+ }, this)) {
+ option = f + ': ' + i.value;
+ d[l++] = new Option(option, option);
+ }
+ }
+ }, this);
+ }
+ },
+
+ updateMessage: function()
+ {
+ if (parent.opener.closed) {
+ alert(IMP.text.contacts_closed);
+ window.close();
+ return;
+ }
+
+ if (!parent.opener.document[this.formname]) {
+ alert(IMP.text.contacts_called);
+ window.close();
+ return;
+ }
+
+ $('selected_addresses').childElements().each(function(s) {
+ var address = s.value, f, field = null, pos, v;
+ pos = address.indexOf(':');
+ f = address.substring(0, pos);
+ address = address.substring(pos + 2, address.length)
+
+ if (f == 'to') {
+ field = parent.opener.document[this.formname].to;
+ } else if (!this.to_only && f == 'cc') {
+ field = parent.opener.document[this.formname].cc;
+ } else if (!this.to_only && f == 'bcc') {
+ field = parent.opener.document[this.formname].bcc;
+ }
+
+ if (!field) {
+ return;
+ }
+
+ // Always delimit with commas.
+ if (field.value.length) {
+ v = field.value.replace(/, +/g, ',').split(',').findAll(function(s) { return s; });
+ field.value = v.join(', ');
+ if (field.value.lastIndexOf(';') != field.value.length - 1) {
+ field.value += ',';
+ }
+ field.value += ' ' + address;
+ } else {
+ field.value = address;
+ }
+ if (address.lastIndexOf(';') != address.length - 1) {
+ field.value += ', ';
+ }
+ }, this);
+
+ window.close();
+ },
+
+ removeAddress: function()
+ {
+ $('selected_addresses').childElements().each(function(o) {
+ if (o.selected) {
+ o.remove();
+ }
+ });
+ },
+
+ onDomLoad: function()
+ {
+ $('contacts').observe('submit', this._passAddresses.bind(this));
+ document.observe('change', this._changeHandler.bindAsEventListener(this));
+ document.observe('click', this._clickHandler.bindAsEventListener(this));
+ document.observe('dblclick', this._dblclickHandler.bindAsEventListener(this));
+ },
+
+ _changeHandler: function(e)
+ {
+ var id = e.element().readAttribute('id');
+
+ switch (id) {
+ case 'search_results':
+ $(id)[0].selected = false;
+ break;
+ }
+ },
+
+ _clickHandler: function(e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = e.element(), id;
+
+ while (Object.isElement(elt)) {
+ id = elt.readAttribute('id');
+
+ switch (id) {
+ case 'btn_add_to':
+ case 'btn_add_cc':
+ case 'btn_add_bcc':
+ this.addAddress(id.substring(8));
+ break;
+
+ case 'btn_update':
+ this.updateMessage();
+ break;
+
+ case 'btn_delete':
+ this.removeAddress();
+ break;
+
+ case 'btn_cancel':
+ window.close();
+ break;
+ }
+
+ elt = elt.up();
+ }
+ },
+
+ _dblclickHandler: function(e)
+ {
+ var elt = e.element();
+ if (!elt.match('SELECT')) {
+ elt = elt.up('SELECT');
+ }
+
+ switch (elt.readAttribute('id')) {
+ case 'search_results':
+ this.addAddress('to');
+ break;
+
+ case 'selected_addresses':
+ this.removeAddress();
+ break;
+ }
+ }
+
+};
+
+document.observe('dom:loaded', ImpContacts.onDomLoad.bind(ImpContacts));
--- /dev/null
+/**
+ * Javascript code used to display a RedBox dialog.
+ *
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@curecanti.org>
+ */
+
+var IMPDialog = {
+
+ display: function(data)
+ {
+ if (Object.isString(data)) {
+ data = decodeURIComponent(data).evalJSON(true);
+ }
+ if (data.dialog_load) {
+ new Ajax.Request(data.dialog_load, { onComplete: this._onComplete.bind(this) });
+ } else {
+ this._display(data);
+ }
+ },
+
+ _onComplete: function(response)
+ {
+ this._display(response.responseJSON.response);
+ },
+
+ _display: function(data)
+ {
+ this.action = data.action;
+ this.params = data.params;
+ this.uri = data.uri;
+
+ var n = new Element('FORM', { action: '#', id: 'RB_confirm' }).insert(
+ new Element('P').insert(data.text)
+ );
+
+ if (data.form) {
+ n.insert(data.form);
+ } else {
+ n.insert(new Element('INPUT', { name: 'dialog_input', type: data.password ? 'password' : 'text', size: 15 }));
+ }
+
+ if (data.ok_text) {
+ n.insert(
+ new Element('INPUT', { type: 'button', className: 'button', value: data.ok_text }).observe('click', this._onClick.bind(this))
+ );
+ }
+
+ n.insert(
+ new Element('INPUT', { type: 'button', className: 'button', value: data.cancel_text }).observe('click', this._close.bind(this))
+ ).observe('keydown', function(e) { if ((e.keyCode || e.charCode) == Event.KEY_RETURN) { e.stop(); this._onClick(e); } }.bind(this));
+
+ RedBox.overlay = true;
+ RedBox.onDisplay = Form.focusFirstElement.curry(n);
+ RedBox.showHtml(n);
+ },
+
+ _close: function()
+ {
+ var c = RedBox.getWindowContents();
+ [ c, c.descendants()].flatten().compact().invoke('stopObserving');
+ RedBox.close();
+ },
+
+ _onClick: function(e)
+ {
+ var params = $H((!this.params || Object.isArray(this.params)) ? {} : this.params);
+ params.update(e.findElement('form').serialize(true));
+
+ new Ajax.Request(this.uri, { parameters: params, onSuccess: this._onSuccess.bind(this), onFailure: this._onFailure.bind(this) });
+ },
+
+ _onSuccess: function(r)
+ {
+ r = r.responseJSON;
+
+ if (r.response.success) {
+ this._close();
+ if (this.action) {
+ if (Object.isFunction(this.action)) {
+ this.action();
+ } else {
+ eval(this.action)();
+ }
+ } else {
+ location.reload();
+ }
+ } else if (r.response.error) {
+ alert(r.response.error);
+ }
+ },
+
+ _onFailure: function(r)
+ {
+ }
+
+};
--- /dev/null
+/**
+ * Provides the javascript for the fetchmailprefs.php script.
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var ImpFetchmailprefs = {
+
+ // The following variables are defined in fetchmailprefs.php:
+ // fetchurl, prefsurl
+ fmprefs_loading: false,
+
+ _accountSubmit: function(isnew)
+ {
+ if (!this.fmprefs_loading &&
+ ((isnew != null) || !$F('account').empty())) {
+ this.fmprefs_loading = true;
+ $('fm_switch').submit();
+ }
+ },
+
+ _driverSubmit: function()
+ {
+ if (!this.fmprefs_loading && $F('fm_driver')) {
+ this.fmprefs_loading = true;
+ $('fm_driver_form').submit();
+ }
+ },
+
+ onDomLoad: function()
+ {
+ document.observe('change', this._changeHandler.bindAsEventListener(this));
+ document.observe('click', this._clickHandler.bindAsEventListener(this));
+ },
+
+ _changeHandler: function(e)
+ {
+ switch (e.element().readAttribute('id')) {
+ case 'account':
+ this._accountSubmit();
+ break;
+
+ case 'fm_driver':
+ this._driverSubmit();
+ break;
+ }
+ },
+
+ _clickHandler: function(e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = e.element();
+
+ while (Object.isElement(elt)) {
+ switch (elt.readAttribute('id')) {
+ case 'btn_delete':
+ $('actionID').setValue('fetchmail_prefs_delete');
+ break;
+
+ case 'btn_create':
+ $('actionID').setValue('fetchmail_create');
+ this._accountSubmit(true);
+ break;
+
+ case 'btn_return':
+ document.location.href = this.prefsurl;
+ break;
+
+ case 'btn_save':
+ $('actionID').setValue('fetchmail_prefs_save');
+ break;
+
+ case 'btn_select':
+ document.location.href = this.fetchurl;
+ break;
+ }
+
+ elt = elt.up();
+ }
+ }
+
+};
+
+document.observe('dom:loaded', ImpFetchmailprefs.onDomLoad.bind(ImpFetchmailprefs));
--- /dev/null
+/**
+ * Provides the javascript for managing message flags.
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var ImpFlagmanagement = {
+ // Variables set by other code: confirm_delete, new_prompt
+
+ addFlag: function()
+ {
+ var category = window.prompt(this.new_prompt, '');
+ if (category) {
+ this._sendData('add', category);
+ }
+ },
+
+ _sendData: function(a, d)
+ {
+ $('flag_action').setValue(a)
+ $('flag_data').setValue(d);
+ $('prefs').submit();
+ },
+
+ clickHandler: function(e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = e.element(), elt2, id;
+
+ while (Object.isElement(elt)) {
+ if (elt.hasClassName('flagcolorpicker')) {
+ elt2 = elt.previous('INPUT');
+ id = elt2.readAttribute('id');
+ new ColorPicker({
+ color: $F(elt2),
+ offsetParent: elt,
+ update: [[ id, 'value' ], [ id, 'background' ]]
+ });
+ e.stop();
+ return;
+ }
+
+ if (elt.hasClassName('flagdelete')) {
+ if (window.confirm(this.confirm_delete)) {
+ this._sendData('delete', elt.previous('INPUT').readAttribute('id'));
+ }
+ e.stop();
+ return;
+ }
+
+ switch (elt.readAttribute('id')) {
+ case 'new_button':
+ this.addFlag();
+ break;
+ }
+
+ elt = elt.up();
+ }
+ },
+
+ resetHandler: function()
+ {
+ $('prefs').getInputs('text').each(function(i) {
+ if (i.readAttribute('id').startsWith('color_')) {
+ i.setStyle({ backgroundColor: $F(i) });
+ }
+ });
+ }
+
+};
+
+document.observe('dom:loaded', function() {
+ var fm = ImpFlagmanagement;
+ document.observe('click', fm.clickHandler.bindAsEventListener(fm));
+ $('prefs').observe('reset', function() { fm.resetHandler.defer(); });
+});
--- /dev/null
+/**
+ * Provides the javascript for the compose.php script (standard view).
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var ImpFolders = {
+
+ // The following variables are defined in folders.php:
+ // displayNames, folders_url
+
+ getChecked: function()
+ {
+ return this.getFolders().findAll(function(e) {
+ return e.checked;
+ });
+ },
+
+ getFolders: function()
+ {
+ return $('fmanager').getInputs(null, 'folder_list[]');
+ },
+
+ selectedFoldersDisplay: function()
+ {
+ var folder = 0, sel = "";
+
+ this.getFolders().each(function(e) {
+ if (e.checked) {
+ sel += this.displayNames[folder] + "\n";
+ }
+ ++folder;
+ }, this);
+
+ return sel.strip();
+ },
+
+ chooseAction: function(e)
+ {
+ var id = (e.element().readAttribute('id') == 'action_choose0') ? 0 : 1,
+ a = $('action_choose' + id),
+ action = $F(a);
+ a.selectedIndex = 0;
+
+ switch (action) {
+ case 'create_folder':
+ this.createMailbox();
+ break;
+
+ case 'rebuild_tree':
+ this.submitAction(action);
+ break;
+
+ default:
+ if (!this.getChecked().size()) {
+ if (action != '') {
+ alert(IMP.text.folders_select);
+ }
+ break;
+ }
+
+ switch (action) {
+ case 'rename_folder':
+ this.renameMailbox();
+ break;
+
+ case 'subscribe_folder':
+ case 'unsubscribe_folder':
+ case 'poll_folder':
+ case 'expunge_folder':
+ case 'nopoll_folder':
+ case 'mark_folder_seen':
+ case 'mark_folder_unseen':
+ case 'delete_folder_confirm':
+ case 'folders_empty_mailbox_confirm':
+ case 'mbox_size':
+ this.submitAction(action);
+ break;
+
+ case 'download_folder':
+ case 'download_folder_zip':
+ this.downloadMailbox(action);
+ break;
+
+ case 'import_mbox':
+ if (this.getChecked().length > 1) {
+ alert(IMP.text.folders_oneselect);
+ } else {
+ this.submitAction(action);
+ }
+ break;
+ }
+
+ break;
+ }
+ },
+
+ submitAction: function(a)
+ {
+ $('actionID').setValue(a);
+ $('fmanager').submit();
+ },
+
+ createMailbox: function()
+ {
+ var count = this.getChecked().size(), mbox;
+ if (count > 1) {
+ window.alert(IMP.text.folders_oneselect);
+ return;
+ }
+
+ mbox = (count == 1)
+ ? window.prompt(IMP.text.folders_subfolder1 + ' ' + this.selectedFoldersDisplay() + ".\n" + IMP.text.folders_subfolder2 + "\n", '')
+ : window.prompt(IMP.text.folders_toplevel, '');
+
+ if (mbox) {
+ $('new_mailbox').setValue(mbox);
+ this.submitAction('create_folder');
+ }
+ },
+
+ downloadMailbox: function(actionid)
+ {
+ if (window.confirm(IMP.text.folders_download1 + "\n" + this.selectedFoldersDisplay() + "\n" + IMP.text.folders_download2)) {
+ this.submitAction(actionid);
+ }
+ },
+
+ renameMailbox: function()
+ {
+ var newnames = '', oldnames = '', j = 0;
+
+ this.getFolders().each(function(f) {
+ if (f.checked) {
+ if (IMP.conf.fixed_folders.indexOf(this.displayNames[j]) != -1) {
+ window.alert(IMP.text.folders_no_rename + ' ' + this.displayNames[j]);
+ } else {
+ var tmp = window.prompt(IMP.text.folders_rename1 + ' ' + this.displayNames[j] + "\n" + IMP.text.folders_rename2, this.displayNames[j]);
+ if (tmp) {
+ newnames += tmp + "\n";
+ oldnames += f.value + "\n";
+ }
+ }
+ }
+ ++j;
+ }, this);
+
+ if (newnames) {
+ $('new_names').setValue(newnames.strip());
+ $('old_names').setValue(oldnames.strip());
+ this.submitAction('rename_folder');
+ }
+ },
+
+ toggleSelection: function()
+ {
+ var count = this.getChecked().size(), folders = this.getFolders(),
+ checked = (count != folders.size());
+ folders.each(function(f) {
+ f.checked = checked;
+ });
+ },
+
+ changeHandler: function(e)
+ {
+ switch (e.element().readAttribute('id')) {
+ case 'action_choose0':
+ case 'action_choose1':
+ this.chooseAction(e);
+ break;
+ }
+ },
+
+ clickHandler: function(e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = e.element();
+
+ while (Object.isElement(elt)) {
+ switch (elt.readAttribute('id')) {
+ case 'btn_import':
+ this.submitAction('import_mbox');
+ break;
+
+ case 'btn_return':
+ document.location.href = this.folders_url;
+ break;
+
+ case 'checkAll0':
+ case 'checkAll1':
+ this.toggleSelection();
+ break;
+ }
+
+ elt = elt.up();
+ }
+ }
+
+};
+
+document.observe('change', ImpFolders.changeHandler.bind(ImpFolders));
+document.observe('click', ImpFolders.clickHandler.bind(ImpFolders));
--- /dev/null
+/**
+ * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var DimpFullmessage = {
+
+ // Variables defaulting to empty/false:
+ // index, mailbox
+ quickreply: function(type)
+ {
+ var func, ob = {};
+ ob[this.mailbox] = [ this.index ];
+
+ $('msgData').hide();
+ $('qreply').show();
+
+ switch (type) {
+ case 'reply':
+ case 'reply_all':
+ case 'reply_list':
+ func = 'GetReplyData';
+ break;
+
+ case 'forward':
+ func = 'GetForwardData';
+ break;
+ }
+
+ DimpCore.doAction(func,
+ { imp_compose: $F('composeCache'),
+ type: type },
+ ob,
+ this.msgTextCallback.bind(this));
+ },
+
+ msgTextCallback: function(result)
+ {
+ if (!result.response) {
+ return;
+ }
+
+ var r = result.response,
+ editor_on = ((r.format == 'html') && !DimpCompose.editor_on),
+ id = (r.identity === null) ? $F('identity') : r.identity,
+ i = DimpCompose.get_identity(id, editor_on);
+
+ $('identity', 'last_identity').invoke('setValue', id);
+
+ DimpCompose.fillForm((i.id[2]) ? ("\n" + i.sig + r.body) : (r.body + "\n" + i.sig), r.header);
+
+ if (r.fwd_list && r.fwd_list.length) {
+ r.fwd_list.each(function(ptr) {
+ DimpCompose.addAttach(ptr.number, ptr.name, ptr.type, ptr.size);
+ });
+ }
+
+ if (editor_on) {
+ DimpCompose.toggleHtmlEditor(true);
+ }
+
+ if (r.imp_compose) {
+ $('composeCache').setValue(r.imp_compose);
+ }
+ },
+
+ /* Click handlers. */
+ clickHandler: function(parentfunc, e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = orig = e.element(), id;
+
+ while (Object.isElement(elt)) {
+ id = elt.readAttribute('id');
+
+ switch (id) {
+ case 'windowclose':
+ window.close();
+ e.stop();
+ return;
+
+ case 'forward_link':
+ case 'reply_link':
+ this.quickreply(id == 'reply_link' ? 'reply' : 'forward');
+ e.stop();
+ return;
+
+ case 'button_deleted':
+ case 'button_ham':
+ case 'button_spam':
+ if (id == 'button_deleted') {
+ DIMP.baseWindow.DimpBase.deleteMsg({ index: this.index, mailbox: this.mailbox });
+ } else {
+ DIMP.baseWindow.DimpBase.reportSpam(id == 'button_spam', { index: this.index, mailbox: this.mailbox });
+ }
+ window.close();
+ e.stop();
+ return;
+
+ case 'msgloglist_toggle':
+ case 'partlist_toggle':
+ tmp = (id == 'partlist_toggle') ? 'partlist' : 'msgloglist';
+ $(tmp + '_col', tmp + '_exp').invoke('toggle');
+ Effect.toggle(tmp, 'blind', {
+ afterFinish: function() {
+ this.resizeWindow();
+ $('msgData').down('DIV.msgBody').setStyle({ overflowY: 'auto' })
+ }.bind(this),
+ beforeSetup: function() {
+ $('msgData').down('DIV.msgBody').setStyle({ overflowY: 'hidden' })
+ },
+ duration: 0.2,
+ queue: {
+ position: 'end',
+ scope: tmp,
+ limit: 2
+ }
+ });
+ break;
+
+ case 'msg_view_source':
+ DimpCore.popupWindow(DimpCore.addURLParam(DIMP.conf.URI_VIEW, { uid: this.index, mailbox: this.mailbox, actionID: 'view_source', id: 0 }, true), DIMP.conf.msg_index + '|' + DIMP.conf.msg_folder);
+ break;
+
+ case 'qreply':
+ if (orig.match('DIV.headercloseimg IMG')) {
+ DimpCompose.confirmCancel();
+ }
+ break;
+ }
+
+ elt = elt.up();
+ }
+
+ parentfunc(e);
+ },
+
+ contextOnClick: function(parentfunc, elt, baseelt, menu)
+ {
+ var id = elt.readAttribute('id');
+
+ switch (id) {
+ case 'ctx_reply_reply':
+ case 'ctx_reply_reply_all':
+ case 'ctx_reply_reply_list':
+ this.quickreply(id.substring(10));
+ break;
+
+ default:
+ parentfunc(elt, baseelt, menu);
+ break;
+ }
+ },
+
+ /* Add a popdown menu to a dimpactions button. */
+ addPopdown: function(bid, ctx)
+ {
+ var bidelt = $(bid);
+ bidelt.insert({ after: new Element('SPAN', { className: 'iconImg popdownImg popdown', id: bid + '_img' }) });
+ DimpCore.DMenu.addElement(bid + '_img', 'ctx_' + ctx, { offset: bidelt.up(), left: true });
+ },
+
+ resizeWindow: function()
+ {
+ var mb = $('msgData').down('DIV.msgBody');
+
+ mb.setStyle({ height: (document.viewport.getHeight() - mb.cumulativeOffset()[1] - parseInt(mb.getStyle('paddingTop'), 10) - parseInt(mb.getStyle('paddingBottom'), 10)) + 'px' });
+ },
+
+ onDomLoad: function()
+ {
+ DimpCore.growler_log = false;
+ DimpCore.init();
+
+ if (DIMP.conf.disable_compose) {
+ tmp = $('reply_link', 'forward_link').compact().invoke('up', 'SPAN').concat([ $('ctx_contacts_new') ]).compact().invoke('remove');
+ } else {
+ this.addPopdown('reply_link', 'replypopdown');
+ }
+
+ /* Set up address linking. */
+ [ 'from', 'to', 'cc', 'bcc', 'replyTo' ].each(function(a) {
+ if (this[a]) {
+ var elt = $('msgHeader' + a.charAt(0).toUpperCase() + a.substring(1)).down('TD', 1);
+ elt.replace(DimpCore.buildAddressLinks(this[a], elt.cloneNode(false)));
+ }
+ }, this);
+
+ /* Add message information. */
+ if (this.log) {
+ $('msgLogInfo').show();
+ DimpCore.updateMsgLog(this.log);
+ }
+
+ this.resizeWindow();
+ }
+
+};
+
+/* ContextSensitive functions. */
+DimpCore.contextOnClick = DimpCore.contextOnClick.wrap(DimpFullmessage.contextOnClick.bind(DimpFullmessage));
+
+/* Click handler. */
+DimpCore.clickHandler = DimpCore.clickHandler.wrap(DimpFullmessage.clickHandler.bind(DimpFullmessage));
+
+/* Attach event handlers. */
+document.observe('dom:loaded', DimpFullmessage.onDomLoad.bind(DimpFullmessage));
+Event.observe(window, 'resize', DimpFullmessage.resizeWindow.bind(DimpFullmessage));
--- /dev/null
+/**
+ * Provides basic IMP javascript functions.
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+document.observe('dom:loaded', function() {
+ if (!window.IMP) {
+ window.IMP = {};
+ }
+
+ window.IMP.menuFolderSubmit = function(clear)
+ {
+ var mf = $('menuform');
+
+ if ((!this.menufolder_load || clear) &&
+ $F(mf.down('SELECT[name="mailbox"]'))) {
+ this.menufolder_load = true;
+ mf.submit();
+ }
+ };
+
+ /**
+ * Use DOM manipulation to un-block images.
+ */
+ window.IMP.unblockImages = function(e)
+ {
+ var elt = e.element().up('TABLE.mimeStatusMessage');
+
+ elt.next('.htmlMessage').select('[blocked]').each(function(e) {
+ var src = decodeURIComponent(e.readAttribute('blocked'));
+ if (e.hasAttribute('src')) {
+ e.writeAttribute('src', src);
+ } else if (e.hasAttribute('background')) {
+ e.writeAttribute('background', src);
+ } else if (e.style.backgroundImage) {
+ e.setStyle({ backgroundImage: 'url(' + src + ')' });
+ }
+ });
+
+ Effect.Fade(elt, {
+ afterFinish: function() { elt.remove(); },
+ duration: 0.6
+ });
+
+ e.stop();
+ };
+
+ // If menu is present, attach event handlers to folder switcher.
+ var tmp = $('openfoldericon');
+ if (tmp) {
+ $('menuform').observe('change', window.IMP.menuFolderSubmit.bind(window.IMP));
+ tmp.down().observe('click', window.IMP.menuFolderSubmit.bind(window.IMP, true));
+ }
+});
--- /dev/null
+/**
+ * Provides the javascript for the login.php script.
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var ImpLogin = {
+ // The following variables are defined in login.php:
+ // dimp_sel, server_key_error
+
+ submit: function(parentfunc)
+ {
+ if ($('imp_server_key') && $F('imp_server_key').startsWith('_')) {
+ alert(this.server_key_error);
+ $('imp_server_key').focus();
+ return;
+ }
+
+ parentfunc();
+ },
+
+ onDomLoad: function()
+ {
+ /* Activate dynamic view. */
+ var o = $('imp_select_view').down('option[value=dimp]').show();
+ if (this.dimp_sel) {
+ o.writeAttribute('selected', 'selected');
+ }
+ }
+};
+
+HordeLogin.submit = HordeLogin.submit.wrap(ImpLogin.submit.bind(ImpLogin));
+document.observe('dom:loaded', ImpLogin.onDomLoad.bind(ImpLogin));
--- /dev/null
+/**
+ * mailbox-dimp.js - Template used to format the rows in the message list
+ * display.
+ *
+ * 'vpData' is a mandatory entry for ID/class information automatically
+ * generated by ViewPort.js.
+ * 'status', 'style', and 'subjectdata' are entries that are internally
+ * created by DimpBase.js.
+ *
+ * See the documentation of prototypejs - Template for the template format:
+ * http://www.prototypejs.org/api/template
+ *
+ * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+DimpBase.message_list_template =
+'<div #{vpData} style="#{style}">' +
+ '<div class="msgStatus">' +
+ '<div class="msCheck"></div>' +
+ '#{status}' +
+ '</div>' +
+ '<div class="msgFrom">#{from}</div>' +
+ '<div class="msgSubject" title="#{subjecttitle}">#{subjectdata}#{subject}</div>' +
+ '<div class="msgDate">#{date}</div>' +
+ '<div class="msgSize">#{size}</div>' +
+'</div>';
--- /dev/null
+/**
+ * Provides the javascript for the mailbox.php script (standard view).
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var ImpMailbox = {
+ // The following variables are defined in mailbox.php:
+ // sortlimit, unread
+
+ anySelected: function()
+ {
+ return $('messages').select('[name="indices[]"]').detect(Form.Element.getValue);
+ },
+
+ selectRow: function(id, select)
+ {
+ [ id ].invoke(select ? 'addClassName' : 'removeClassName', 'selectedRow');
+ id.down('INPUT.checkbox').setValue(select);
+ },
+
+ confirmDialog: function(url, msg)
+ {
+ RedBox.overlay = true;
+ RedBox.showHtml('<div id="RB_confirm"><p>' + msg + '</p><input type="button" class="button" onclick="window.location=\'' + url + '\';" value="' + IMP.text.yes + '" />' +
+ '<input type="button" class="button" onclick="RedBox.close();" value="' + IMP.text.no + '" /></div>');
+ },
+
+ submit: function(actID)
+ {
+ if (!this.anySelected()) {
+ alert(IMP.text.mailbox_submit);
+ return;
+ }
+
+ switch (actID) {
+ case 'delete_messages':
+ if (IMP.conf.pop3 && !confirm(IMP.text.mailbox_delete)) {
+ return;
+ }
+ break;
+
+ case 'spam_report':
+ if (!confirm(IMP.text.spam_report)) {
+ return;
+ }
+ break;
+
+ case 'nostpam_report':
+ if (!confirm(IMP.text.notspam_report)) {
+ return;
+ }
+ break;
+ }
+
+ $('actionID').setValue(actID);
+ $('messages').submit();
+ },
+
+ selectRange: function(e)
+ {
+ // elt = checkbox element
+ var elt = e.element(),
+ tr = elt.up('TR'),
+ checked = $F(elt),
+ end, start;
+
+ if (this.startrange && e.shiftKey) {
+ if (this.startrange != elt) {
+ // Dirty trick - use position in page to determine which way
+ // to traverse
+ if (this.startrange.offsetTop < tr.offsetTop) {
+ start = this.startrange.next();
+ end = tr;
+ } else {
+ start = tr;
+ end = this.startrange.previous();
+ }
+
+ do {
+ this.selectRow(start, checked);
+ if (start == end) {
+ break;
+ }
+ start = start.next();
+ } while (start);
+ }
+ } else {
+ this.selectRow(tr, checked);
+ }
+
+ this.startrange = tr;
+ },
+
+ updateFolders: function(form)
+ {
+ var tm1 = $('targetMailbox1'),
+ tm2 = $('targetMailbox2');
+
+ if (tm2) {
+ if ((form == 1 && $F(tm1) != "") ||
+ (form == 2 && $F(tm2) != "")) {
+ tm1.selectedIndex = tm2.selectedIndex = (form == 1)
+ ? tm1.selectedIndex
+ : tm2.selectedIndex;
+ }
+ }
+ },
+
+ _transfer: function(actID)
+ {
+ var newFolder, tmbox;
+
+ if (this.anySelected()) {
+ tmbox = $('targetMbox');
+ tmbox.setValue($F('targetMailbox1'));
+
+ // Check for a mailbox actually being selected.
+ if ($F(tmbox) == '*new*') {
+ newFolder = prompt(IMP.text.newfolder, '');
+ if (newFolder != null && newFolder != '') {
+ $('newMbox').setValue(1);
+ tmbox.setValue(newFolder);
+ this.submit(actID);
+ }
+ } else {
+ if ($F(tmbox) == '') {
+ alert(IMP.text.target_mbox);
+ } else {
+ this.submit(actID);
+ }
+ }
+ } else {
+ alert(IMP.text.mailbox_selectone);
+ }
+ },
+
+ flagMessages: function(form)
+ {
+ var f1 = $('flag1'), f2 = $('flag2');
+
+ if ((form == 1 && $F(f1) != "") ||
+ (form == 2 && $F(f2) != "")) {
+ if (this.anySelected()) {
+ $('messages').down('[name=flag]').setValue((form == 1) ? $F(f1) : $F(f2));
+ this.submit('flag_messages');
+ } else {
+ if (form == 1) {
+ f1.selectedIndex = 0;
+ } else {
+ f2.selectedIndex = 0;
+ }
+ alert(IMP.text.mailbox_selectone);
+ }
+ }
+ },
+
+ getMessage: function(id, offset)
+ {
+ if (!offset) {
+ return id;
+ }
+
+ var mlist = $H(this.messagelist).keys(),
+ i = mlist.indexOf(id),
+ j = i + offset;
+
+ if (i != -1) {
+ if (j >= 0 && j < mlist.length) {
+ return mlist[j];
+ }
+ }
+
+ return '';
+ },
+
+ changeHandler: function(e)
+ {
+ var id = e.element().readAttribute('id');
+
+ if (id) {
+ if (id.startsWith('flag')) {
+ this.flagMessages(id.substring(4));
+ } else if (id.startsWith('targetMailbox')) {
+ this.updateFolders(id.substring(13));
+ }
+ }
+ },
+
+ clickHandler: function(e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = e.element(), id;
+
+ while (Object.isElement(elt)) {
+ if (elt.match('.msgactions A.widget')) {
+ if (elt.hasClassName('moveAction')) {
+ this._transfer('move_messages');
+ } else if (elt.hasClassName('copyAction')) {
+ this._transfer('copy_messages');
+ } else if (elt.hasClassName('permdeleteAction')) {
+ if (confirm(IMP.text.mailbox_delete)) {
+ this.submit('delete_messages');
+ }
+ } else if (elt.hasClassName('deleteAction')) {
+ this.submit('delete_messages');
+ } else if (elt.hasClassName('undeleteAction')) {
+ this.submit('undelete_messages');
+ } else if (elt.hasClassName('blacklistAction')) {
+ this.submit('blacklist');
+ } else if (elt.hasClassName('whitelistAction')) {
+ this.submit('whitelist');
+ } else if (elt.hasClassName('forwardAction')) {
+ this.submit('fwd_digest');
+ } else if (elt.hasClassName('spamAction')) {
+ this.submit('spam_report');
+ } else if (elt.hasClassName('notspamAction')) {
+ this.submit('notspam_report');
+ } else if (elt.hasClassName('viewAction')) {
+ this.submit('view_messages');
+ } else if (elt.hasClassName('hideAction') || elt.hasClassName('purgeAction')) {
+ return;
+ }
+
+ e.stop();
+ return;
+ } else if (elt.hasClassName('checkbox')) {
+ this.selectRange(e);
+ // Fall through to elt.up() call below.
+ }
+
+ id = elt.readAttribute('id');
+ if (!id) {
+ elt = elt.up();
+ continue;
+ }
+
+ switch (id) {
+ case 'checkheader':
+ case 'checkAll':
+ if (id == 'checkheader') {
+ $('checkAll').checked = !$('checkAll').checked;
+ }
+
+ $('messages').select('TABLE.messageList TR[id]').each(function(i, s) {
+ this.selectRow(i, $F('checkAll'));
+ }, this);
+ return;
+ }
+
+ if (!this.sortlimit &&
+ elt.match('TH') &&
+ elt.up('TABLE.messageList')) {
+ document.location.href = elt.down('A').href;
+ }
+
+ elt = elt.up();
+ }
+ },
+
+ keyDownHandler: function(e)
+ {
+ var elt = e.element(),
+ key = e.keyCode,
+ loc, search, tmp;
+
+ if (e.altKey || e.ctrlKey) {
+ if (!(key == Event.KEY_UP || key == Event.KEY_DOWN)) {
+ return;
+ }
+
+ if (!this.cursor) {
+ this.cursor = elt.up('TABLE.messageList TR');
+ }
+
+ if (this.cursor) {
+ if (e.altKey) {
+ this.selectRow(this.cursor, !$F(this.cursor.down('INPUT.checkbox')));
+ }
+
+ switch (key) {
+ case Event.KEY_UP:
+ this.cursor = this.cursor.previous();
+ if (!this.cursor.readAttribute('id')) {
+ search = 'last';
+ }
+ break;
+
+ case Event.KEY_DOWN:
+ this.cursor = this.cursor.next();
+ if (!this.cursor) {
+ search = 'first';
+ }
+ break;
+ }
+ } else {
+ search = key == Event.KEY_DOWN ? 'first' : 'last';
+ }
+
+ if (search) {
+ tmp = $('messages').select('TABLE.messageList TR[id]');
+ this.cursor = (search == 'first') ? tmp.first() : tmp.last();
+ }
+
+ this.cursor.down('TD A.mboxSubject').focus();
+ } else if (key == 32 && this.cursor) {
+ this.selectRow(this.cursor, !$F(this.cursor.down('INPUT.checkbox')));
+ } else if (!e.shiftKey) {
+ if (key == Event.KEY_LEFT && $('prev')) {
+ loc = $('prev');
+ } else if (key == Event.KEY_RIGHT && $('next')) {
+ loc = $('next');
+ }
+
+ if (loc) {
+ document.location.href = loc.readAttribute('href');
+ }
+ return;
+ } else {
+ return;
+ }
+
+ e.stop();
+ },
+
+ submitHandler: function(e)
+ {
+ if (e.element().readAttribute('id').startsWith('select')) {
+ e.stop();
+ }
+ }
+
+};
+
+document.observe('dom:loaded', function() {
+ var im = ImpMailbox;
+
+ document.observe('change', im.changeHandler.bindAsEventListener(im));
+ document.observe('click', im.clickHandler.bindAsEventListener(im));
+ document.observe('keydown', im.keyDownHandler.bindAsEventListener(im));
+ document.observe('submit', im.submitHandler.bindAsEventListener(im));
+
+ if (window.fluid) {
+ try {
+ window.fluid.setDockBadge(ImpMailbox.unread);
+ } catch (e) {}
+ }
+});
--- /dev/null
+/**
+ * Provides the javascript for the message.php script (standard view).
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var ImpMessage = {
+
+ _arrowHandler: function(e)
+ {
+ if (e.altKey || e.shiftKey || e.ctrlKey) {
+ return;
+ }
+
+ switch (e.keyCode || e.charCode) {
+ case Event.KEY_LEFT:
+ if ($('prev')) {
+ document.location.href = $('prev').href;
+ }
+ break;
+
+ case Event.KEY_RIGHT:
+ if ($('next')) {
+ document.location.href = $('next').href;
+ }
+ break;
+ }
+ },
+
+ submit: function(actID)
+ {
+ switch (actID) {
+ case 'spam_report':
+ if (!window.confirm(IMP.text.spam_report)) {
+ return;
+ }
+ break;
+
+ case 'notspam_report':
+ if (!window.confirm(IMP.text.notspam_report)) {
+ return;
+ }
+ break;
+ }
+
+ $('actionID').setValue(actID);
+ $('messages').submit();
+ },
+
+ flagMessage: function(form)
+ {
+ var f1 = $('flag1'), f2 = $('flag2');
+
+ if ((form == 1 && $F(f1) != "") ||
+ (form == 2 && $F(f2) != "")) {
+ $('messages').down('[name=flag]').setValue((form == 1) ? $F(f1) : $F(f2));
+ this.submit('flag_message');
+ }
+ },
+
+ _transfer: function(actID)
+ {
+ var newFolder, tmbox = $('targetMbox');
+ tmbox.setValue($F('target1'));
+
+ // Check for a mailbox actually being selected.
+ if ($F(tmbox) == '*new*') {
+ newFolder = window.prompt(IMP.text.newfolder, '');
+ if (newFolder != null && newFolder != '') {
+ $('newMbox').setValue(1);
+ tmbox.setValue(newFolder);
+ this.submit(actID);
+ }
+ } else {
+ if (!$F(tmbox)) {
+ window.alert(IMP.text.target_mbox);
+ } else {
+ this.submit(actID);
+ }
+ }
+ },
+
+ updateFolders: function(form)
+ {
+ var f = (form == 1) ? 2 : 1;
+ $('target' + f).selectedIndex = $('target' + form).selectedIndex;
+ },
+
+ /* Function needed for IE compatibilty with drop-down menus. */
+ _messageActionsHover: function()
+ {
+ var iefix = new Element('IFRAME', { scrolling: 'no', frameborder: 0 }).setStyle({ position: 'absolute' }).hide();
+
+ // This can not appear in the new Element() call - Bug #5887
+ iefix.writeAttribute('src', 'javascript:false;');
+
+ $$('UL.msgactions LI').each(function(li) {
+ var fixcopy, ul = li.down('UL'), zindex;
+ if (!ul) {
+ return;
+ }
+
+ fixcopy = iefix.cloneNode(false);
+ li.insert(fixcopy);
+ fixcopy.clonePosition(ul);
+
+ zindex = li.getStyle('zIndex');
+ if (zindex == '') {
+ li.setStyle({ zIndex: 2 });
+ fixcopy.setStyle({ zIndex: 1 });
+ } else {
+ fixcopy.setStyle({ zIndex: parseInt(zindex) - 1 });
+ }
+
+ li.observe('mouseout', function() {
+ this.removeClassName('hover');
+ li.down('iframe').hide();
+ });
+ li.observe('mouseover', function() {
+ this.addClassName('hover');
+ li.down('iframe').show();
+ });
+ });
+ },
+
+ onDomLoad: function()
+ {
+ // Set up left and right arrows to go to the previous/next page.
+ document.observe('keydown', this._arrowHandler.bindAsEventListener(this));
+ document.observe('change', this._changeHandler.bindAsEventListener(this));
+ document.observe('click', this._clickHandler.bindAsEventListener(this));
+
+ if (Prototype.Browser.IE) {
+ this._messageActionsHover();
+ }
+ },
+
+ _changeHandler: function(e)
+ {
+ var id = e.element().readAttribute('id');
+
+ if (id.startsWith('flag')) {
+ this.flagMessage(id.substring(4));
+ } else if (id.startsWith('target')) {
+ this.updateFolders(id.substring(6));
+ }
+ },
+
+ _clickHandler: function(e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = e.element();
+
+ while (Object.isElement(elt)) {
+ if (elt.match('.msgactions A.widget')) {
+ if (elt.hasClassName('moveAction')) {
+ this._transfer('move_message');
+ } else if (elt.hasClassName('copyAction')) {
+ this._transfer('copy_message');
+ } else if (elt.hasClassName('spamAction')) {
+ this.submit('spam_report');
+ } else if (elt.hasClassName('notspamAction')) {
+ this.submit('notspam_report');
+ } else if (elt.hasClassName('printAction')) {
+ window.print();
+ }
+ } else if (elt.hasClassName('unblockImageLink')) {
+ IMP.unblockImages(e);
+ } else if (elt.match('SPAN.toggleQuoteShow')) {
+ [ elt, elt.next() ].invoke('toggle');
+ Effect.BlindDown(elt.next(1), { duration: 0.2, queue: { position: 'end', scope: 'showquote', limit: 2 } });
+ } else if (elt.match('SPAN.toggleQuoteHide')) {
+ [ elt, elt.previous() ].invoke('toggle');
+ Effect.BlindUp(elt.next(), { duration: 0.2, queue: { position: 'end', scope: 'showquote', limit: 2 } });
+ }
+
+ elt = elt.up();
+ }
+ }
+
+};
+
+document.observe('dom:loaded', ImpMessage.onDomLoad.bind(ImpMessage));
--- /dev/null
+/**
+ * Provides the javascript for the search.php script (standard view).
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var ImpSearch = {
+ // The following variables are defined in search.php:
+ // inverse_sub, not_search, search_date
+
+ _toggleAll: function(checked)
+ {
+ $('search').getInputs(null, 'search_folders[]').each(function(e) {
+ e.checked = checked;
+ });
+ },
+
+ _dateCheck: function(field)
+ {
+ var m = $('search_' + field + '_month'),
+ d = $('search_' + field + '_day'),
+ y = $('search_' + field + '_year');
+
+ if (m.selectedIndex == 0) {
+ m.selectedIndex = this.search_date.m;
+ }
+
+ if (d.selectedIndex == 0) {
+ d.selectedIndex = this.search_date.d;
+ }
+
+ if (y.value == "") {
+ y.value = this.search_date.y;
+ }
+ },
+
+ _formCheck: function()
+ {
+ if (this.not_search &&
+ (!$('preselected_folders') || !$F('preselected_folders'))) {
+ if (!Form.getInputs('search', null, 'search_folders[]').detect(function(e) { return e.checked; })) {
+ alert(IMP.text.search_select);
+ return;
+ }
+ }
+
+ $('actionID').setValue('do_search');
+ },
+
+ _reset: function()
+ {
+ $('actionID').setValue('reset_search');
+ $('search').submit();
+ },
+
+ _saveCache: function()
+ {
+ $('edit_query').setValue($F('save_cache'));
+ $('search').submit();
+ },
+
+ _deleteField: function(i)
+ {
+ $('delete_field_id').setValue(i);
+ $('actionID').setValue('delete_field');
+ $('search').submit();
+ },
+
+ _showSubscribed: function(i)
+ {
+ $('show_subscribed_only').setValue(i);
+ $('search').submit();
+ },
+
+ changeHandler: function(e)
+ {
+ var id = e.element().readAttribute('id');
+
+ switch (id) {
+ case 'save_cache':
+ this._saveCache();
+ break;
+
+ default:
+ if (id.startsWith('field_')) {
+ $('search').submit();
+ } else if (id.startsWith('search_date_')) {
+ this._dateCheck('on');
+ }
+ break;
+ }
+ },
+
+ clickHandler: function(e)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = e.element();
+
+ while (Object.isElement(elt)) {
+ if (elt.hasClassName('searchSubmit')) {
+ this._formCheck();
+ } else if (elt.hasClassName('searchReset')) {
+ this._reset();
+ } else if (elt.hasClassName('searchDelete')) {
+ this._deleteField(elt.readAttribute('fid'));
+ } else {
+ switch (elt.readAttribute('id')) {
+ case 'link_sel_all':
+ this._toggleAll(true);
+ break;
+
+ case 'link_sel_none':
+ this._toggleAll(false);
+ break;
+
+ case 'link_sub':
+ this._showSubscribed(this.inverse_sub);
+ break;
+
+ case 'search_match_and':
+ case 'search_match_or':
+ if ($('field_1')) {
+ $('search').submit();
+ }
+ break;
+ }
+ }
+
+ elt = elt.up();
+ }
+ }
+
+};
+
+document.observe('change', ImpSearch.changeHandler.bind(ImpSearch));
+document.observe('click', ImpSearch.clickHandler.bind(ImpSearch));
+++ /dev/null
-/**
- * ContextSensitive: a library for generating context-sensitive content on
- * HTML elements. It will take over the click/oncontextmenu functions for the
- * document, and works only where these are possible to override. It allows
- * contextmenus to be created via both a left and right mouse click.
- *
- * Requires prototypejs 1.6+ and scriptaculous 1.8+ (effects.js only).
- *
- * Original code by Havard Eide (http://eide.org/) released under the MIT
- * license.
- *
- * 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 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.
- *
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @author Michael Slusarz <slusarz@horde.org>
- */
-
-var ContextSensitive = Class.create({
-
- initialize: function(opts)
- {
- this.baseelt = null;
- this.current = [];
- this.elements = $H();
- this.opts = opts || {};
- this.submenus = $H();
- this.triggers = [];
-
- document.observe('contextmenu', this._rightClickHandler.bindAsEventListener(this));
- document.observe('click', this._leftClickHandler.bindAsEventListener(this));
- document.observe(Prototype.Browser.Gecko ? 'DOMMouseScroll' : 'mousescroll', this.close.bind(this));
- },
-
- /**
- * Elements are of type ContextSensitive.Element.
- */
- addElement: function(id, target, opts)
- {
- var left = Boolean(opts.left);
- if (id && !this.validElement(id, left)) {
- this.elements.set(id + Number(left), new ContextSensitive.Element(id, target, opts));
- }
- },
-
- /**
- * Remove a registered element.
- */
- removeElement: function(id)
- {
- this.elements.unset(id + '0');
- this.elements.unset(id + '1');
- },
-
- /**
- * Hide the currently displayed element(s).
- */
- close: function()
- {
- this._closeMenu(0, true);
- },
-
- /**
- * Close all menus below a specified level.
- */
- _closeMenu: function(idx, immediate)
- {
- if (this.current.size()) {
- this.current.splice(idx, this.current.size() - idx).each(function(s) {
- // Fade-out on final display.
- if (!immediate && idx == 0) {
- Effect.Fade(s, { duration: 0.15 });
- } else {
- $(s).hide();
- }
- });
-
- this.triggers.splice(idx, this.triggers.size() - idx).each(function(s) {
- $(s).removeClassName('contextHover');
- });
-
- if (idx == 0) {
- this.baseelt = null;
- }
- }
- },
-
- /**
- * Returns the current displayed menu element ID, if any. If more than one
- * submenu is open, returns the last ID opened.
- */
- currentmenu: function()
- {
- return this.current.last();
- },
-
- /**
- * Get a valid element (the ones that can be right-clicked) based
- * on a element ID.
- */
- validElement: function(id, left)
- {
- return this.elements.get(id + Number(Boolean(left)));
- },
-
- /**
- * Set the disabled flag of an event.
- */
- disable: function(id, left, disable)
- {
- var e = this.validElement(id, left);
- if (e) {
- e.disable = disable;
- }
- },
-
- /**
- * Called when a left click event occurs. Will return before the
- * element is closed if we click on an element inside of it.
- */
- _leftClickHandler: function(e)
- {
- var base, elt, elt_up, trigger;
-
- // Check for a right click. FF on Linux triggers an onclick event even
- // w/a right click, so disregard.
- if (e.isRightClick()) {
- return;
- }
-
- // Check for click in open contextmenu.
- if (this.current.size()) {
- elt = e.element();
- if (!elt.match('A')) {
- elt = elt.up('A');
- if (!elt) {
- this._rightClickHandler(e, true);
- return;
- }
- }
- elt_up = elt.up();
-
- if (elt_up && elt_up.hasClassName('contextMenu')) {
- e.stop();
-
- if (elt.hasClassName('contextSubmenu') &&
- elt_up.readAttribute('id') != this.currentmenu()) {
- this._closeMenu(this.current.indexOf(elt.readAttribute('id')));
- } else {
- base = this.baseelt;
- trigger = this.triggers.last();
- this.close();
- if (this.opts.onClick) {
- this.opts.onClick(elt, base, trigger);
- }
- }
- return;
- }
- }
-
- // Check if the mouseclick is registered to an element now.
- this._rightClickHandler(e, true);
- },
-
- /**
- * Called when a right click event occurs.
- */
- _rightClickHandler: function(e, left)
- {
- if (this.trigger(e.element(), left, e.pointerX(), e.pointerY())) {
- e.stop();
- };
- },
-
- /**
- * Display context menu if valid element has been activated.
- */
- trigger: function(target, leftclick, x, y)
- {
- var ctx, el, el_id, offset, offsets, voffsets;
-
- [ target ].concat(target.ancestors()).find(function(n) {
- ctx = this.validElement(n.id, leftclick);
- return ctx;
- }, this);
-
- // Return if event not found or event is disabled.
- if (!ctx || ctx.disable) {
- this.close();
- return false;
- }
-
- // Try to retrieve the context-sensitive element we want to
- // display. If we can't find it we just return.
- el = $(ctx.ctx);
- if (!el) {
- this.close();
- return false;
- }
-
- el_id = el.readAttribute('id');
- if (leftclick && el_id == this.currentmenu()) {
- return false;
- }
-
- this.close();
-
- // Register the element that was clicked on.
- this.baseelt = target;
-
- offset = ctx.opts.offset;
- if (!offset && (Object.isUndefined(x) || Object.isUndefined(y))) {
- offset = target.readAttribute('id');
- }
- offset = $(offset);
-
- if (offset) {
- offsets = offset.viewportOffset();
- voffsets = document.viewport.getScrollOffsets();
- x = offsets[0] + voffsets.left;
- y = offsets[1] + offset.getHeight() + voffsets.top;
- }
-
- this._displayMenu(el, x, y);
- this.triggers.push(el_id);
-
- return true;
- },
-
- /**
- * Display the [sub]menu on the screen.
- */
- _displayMenu: function(elt, x, y)
- {
- // Get window/element dimensions
- var id = elt.readAttribute('id'),
- size = elt.getDimensions(),
- v = document.viewport.getDimensions();
-
- // Make sure context window is entirely on screen
- if ((y + size.height) > v.height) {
- y = v.height - size.height - 10;
- }
- if ((x + size.width) > v.width) {
- x = v.width - size.width - 10;
- }
-
- if (this.opts.onShow) {
- this.opts.onShow(id, this.baseelt);
- }
-
- elt.setStyle({ left: x + 'px', top: y + 'px' })
-
- if (this.current.size()) {
- elt.show();
- } else {
- // Fade-in on initial display.
- Effect.Appear(elt, { duration: 0.15 });
- }
-
- this.current.push(id);
- },
-
- /**
- * Add a submenu to an existing menu.
- */
- addSubMenu: function(id, submenu)
- {
- if (!this.submenus.get(id)) {
- if (!this.submenus.size()) {
- document.observe('mouseover', this._mouseoverHandler.bindAsEventListener(this));
- }
- this.submenus.set(id, submenu);
- $(submenu).addClassName('contextMenu');
- $(id).addClassName('contextSubmenu');
- }
- },
-
- /**
- * Mouseover DOM Event handler.
- */
- _mouseoverHandler: function(e)
- {
- if (!this.current.size()) {
- return;
- }
-
- var cm = this.currentmenu(),
- elt = e.element(),
- elt_up = elt.up(),
- id = elt.readAttribute('id'),
- id_div, offsets, sub, voffsets, x, y;
-
- if (elt_up == document) {
- return;
- }
-
- id_div = elt_up.readAttribute('id');
-
- if (elt.hasClassName('contextSubmenu')) {
- sub = this.submenus.get(id);
- if (sub != cm || this.currentmenu() != id) {
- if (id_div != cm) {
- this._closeMenu(this.current.indexOf(id_div) + 1);
- }
-
- offsets = elt.viewportOffset();
- voffsets = document.viewport.getScrollOffsets();
- x = offsets[0] + voffsets.left + elt.getWidth();
- y = offsets[1] + voffsets.top;
- this._displayMenu($(sub), x, y, id);
- this.triggers.push(id);
- elt.addClassName('contextHover');
- }
- } else if ((this.current.size() > 1) &&
- elt_up.hasClassName('contextMenu') &&
- id_div != cm) {
- this._closeMenu(this.current.indexOf(id));
- }
- }
-
-});
-
-ContextSensitive.Element = Class.create({
-
- // opts: 'left' -> monitor left click; 'offset' -> id of element used to
- // determine offset placement
- initialize: function(id, target, opts)
- {
- this.id = id;
- this.ctx = target;
- this.opts = opts;
- this.opts.left = Boolean(opts.left);
- this.disable = false;
-
- target = $(target);
- if (target) {
- target.addClassName('contextMenu');
- }
- }
-
-});
+++ /dev/null
-/**
- * DimpBase.js - Javascript used in the base DIMP page.
- *
- * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var DimpBase = {
- // Vars used and defaulting to null/false:
- // cfolderaction, folder, folderswitch, offset, pollPE, pp, sfolder,
- // showunsub, uid, viewport
- // message_list_template set via templates/javascript/mailbox.js
- bcache: $H(),
- cacheids: {},
- lastrow: -1,
- pivotrow: -1,
- ppcache: {},
- ppfifo: [],
- tcache: {},
-
- // Preview pane cache size is 20 entries. Given that a reasonable guess
- // of an average e-mail size is 10 KB (including headers), also make
- // an estimate that the JSON data size will be approx. 10 KB. 200 KB
- // should be a fairly safe caching value for any recent browser.
- ppcachesize: 20,
-
- // Message selection functions
-
- // vs = (ViewPort_Selection) A ViewPort_Selection object.
- // opts = (object) Boolean options [delay, right]
- _select: function(vs, opts)
- {
- var d = vs.get('rownum');
- if (d.size() == 1) {
- this.lastrow = this.pivotrow = d.first();
- }
-
- this.toggleButtons();
-
- if ($('previewPane').visible()) {
- if (opts.right) {
- this.clearPreviewPane();
- } else {
- if (opts.delay) {
- (this.bcache.get('initPP') || this.bcache.set('initPP', this.initPreviewPane.bind(this))).delay(opts.delay);
- } else {
- this.initPreviewPane();
- }
- }
- }
- },
-
- // vs = (ViewPort_Selection) A ViewPort_Selection object.
- // opts = (object) Boolean options [right]
- _deselect: function(vs, opts)
- {
- var sel = this.viewport.getSelected(),
- count = sel.size();
- if (!count) {
- this.lastrow = this.pivotrow = -1;
- }
-
- this.toggleButtons();
- if (opts.right || !count) {
- this.clearPreviewPane();
- } else if ((count == 1) && $('previewPane').visible()) {
- this.loadPreview(sel.get('dataob').first());
- }
- },
-
- // id = (string) DOM ID
- // opts = (Object) Boolean options [ctrl, right, shift]
- msgSelect: function(id, opts)
- {
- var bounds,
- row = this.viewport.createSelection('domid', id),
- rownum = row.get('rownum').first(),
- sel = this.isSelected('domid', id),
- selcount = this.selectedCount();
-
- this.lastrow = rownum;
-
- // Some browsers need to stop the mousedown event before it propogates
- // down to the browser level in order to prevent text selection on
- // drag/drop actions. Clicking on a message should always lose focus
- // from the search input, because the user may immediately start
- // keyboard navigation after that. Thus, we need to ensure that a
- // message click loses focus on the search input.
- if ($('qsearch')) {
- $('qsearch_input').blur();
- }
-
- if (opts.shift) {
- if (selcount) {
- if (!sel || selcount != 1) {
- bounds = [ rownum, this.pivotrow ];
- this.viewport.select($A($R(bounds.min(), bounds.max())), { range: true });
- }
- return;
- }
- } else if (opts.ctrl) {
- this.pivotrow = rownum;
- if (sel) {
- this.viewport.deselect(row, { right: opts.right });
- return;
- } else if (opts.right || selcount) {
- this.viewport.select(row, { add: true, right: opts.right });
- return;
- }
- }
-
- this.viewport.select(row, { right: opts.right });
- },
-
- selectAll: function()
- {
- this.viewport.select($A($R(1, this.viewport.getMetaData('total_rows'))), { range: true });
- },
-
- isSelected: function(format, data)
- {
- return this.viewport.getSelected().contains(format, data);
- },
-
- selectedCount: function()
- {
- return (this.viewport) ? this.viewport.getSelected().size() : 0;
- },
-
- resetSelected: function()
- {
- if (this.viewport) {
- this.viewport.deselect(this.viewport.getSelected(), { clearall: true });
- }
- this.toggleButtons();
- this.clearPreviewPane();
- },
-
- // num = (integer) See absolute.
- // absolute = Is num an absolute row number - from 1 -> page_size (true) -
- // or a relative change from the current selected value (false)
- // If no current selected value, the first message in the
- // current viewport is selected.
- moveSelected: function(num, absolute)
- {
- var curr, curr_row, row, row_data, sel;
-
- if (absolute) {
- if (!this.viewport.getMetaData('total_rows')) {
- return;
- }
- curr = num;
- } else {
- if (num == 0) {
- return;
- }
-
- sel = this.viewport.getSelected();
- switch (sel.size()) {
- case 0:
- curr = this.viewport.currentOffset();
- curr += (num > 0) ? 1 : this.viewport.getPageSize('current');
- break;
-
- case 1:
- curr_row = sel.get('dataob').first();
- curr = curr_row.rownum + num;
- break;
-
- default:
- sel = sel.get('rownum');
- curr = (num > 0 ? sel.max() : sel.min()) + num;
- break;
- }
- curr = (num > 0) ? Math.min(curr, this.viewport.getMetaData('total_rows')) : Math.max(curr, 1);
- }
-
- row = this.viewport.createSelection('rownum', curr);
- if (row.size()) {
- row_data = row.get('dataob').first();
- if (!curr_row || row_data.imapuid != curr_row.imapuid) {
- this.viewport.scrollTo(row_data.rownum);
- this.viewport.select(row, { delay: 0.3 });
- }
- } else {
- this.offset = curr;
- this.viewport.requestContentRefresh(curr - 1);
- }
- },
- // End message selection functions
-
- go: function(loc, data)
- {
- var app, f, separator;
-
- /* If switching from options, we need to reload page to pick up any
- * prefs changes. */
- if (this.folder === null &&
- loc != 'options' &&
- $('appoptions') &&
- $('appoptions').hasClassName('on')) {
- return DimpCore.redirect(DIMP.conf.URI_DIMP + '#' + loc, true);
- }
-
- if (loc.startsWith('compose:')) {
- return;
- }
-
- if (loc.startsWith('msg:')) {
- separator = loc.indexOf(':', 4);
- f = loc.substring(4, separator);
- this.uid = loc.substring(separator + 1);
- loc = 'folder:' + f;
- // Now fall through to the 'folder:' check below.
- }
-
- if (loc.startsWith('folder:')) {
- f = loc.substring(7);
- if (this.folder != f || !$('dimpmain_folder').visible()) {
- this.highlightSidebar(this.getFolderId(f));
- if (!$('dimpmain_folder').visible()) {
- $('dimpmain_portal').hide();
- $('dimpmain_folder').show();
- }
- // This catches the refresh case - no need to re-add to history
- if (!Object.isUndefined(this.folder)) {
- this._addHistory(loc);
- }
- }
- this.loadMailbox(f);
- return;
- }
-
- this.folder = null;
- $('dimpmain_folder').hide();
- $('dimpmain_portal').update(DIMP.text.loading).show();
-
- if (loc.startsWith('app:')) {
- app = loc.substr(4);
- if (app == 'imp') {
- this.go('folder:INBOX');
- return;
- }
- this.highlightSidebar('app' + app);
- this._addHistory(loc, data);
- if (data) {
- this.iframeContent(loc, data);
- } else if (DIMP.conf.app_urls[app]) {
- this.iframeContent(loc, DIMP.conf.app_urls[app]);
- }
- return;
- }
-
- switch (loc) {
- case 'portal':
- this.highlightSidebar('appportal');
- this._addHistory(loc);
- DimpCore.setTitle(DIMP.text.portal);
- DimpCore.doAction('ShowPortal', {}, null, this.bcache.get('portalC') || this.bcache.set('portalC', this._portalCallback.bind(this)));
- break;
-
- case 'options':
- this.highlightSidebar('appoptions');
- this._addHistory(loc);
- DimpCore.setTitle(DIMP.text.prefs);
- this.iframeContent(loc, DIMP.conf.URI_PREFS_IMP);
- break;
- }
- },
-
- _addHistory: function(loc, data)
- {
- if (Horde.dhtmlHistory.getCurrentLocation() != loc) {
- Horde.dhtmlHistory.add(loc, data);
- }
- },
-
- highlightSidebar: function(id)
- {
- // Folder bar may not be fully loaded yet.
- if ($('foldersLoading').visible()) {
- this.highlightSidebar.bind(this, id).defer();
- return;
- }
-
- var curr = $('sidebarPanel').down('.on'),
- elt = $(id);
-
- if (!elt || curr == elt) {
- return;
- }
-
- if (!elt.match('LI')) {
- elt = elt.up();
- if (!elt) {
- return;
- }
- }
-
- if (curr) {
- curr.removeClassName('on');
- }
- elt.addClassName('on');
-
- this._toggleSubFolder(elt, 'exp');
- },
-
- iframeContent: function(name, loc)
- {
- if (name === null) {
- name = loc;
- }
-
- var container = $('dimpmain_portal'), iframe;
- if (!container) {
- DimpCore.showNotifications([ { type: 'horde.error', message: 'Bad portal!' } ]);
- return;
- }
-
- iframe = new Element('IFRAME', { id: 'iframe' + name, className: 'iframe', frameBorder: 0, src: loc });
- this._resizeIE6Iframe(iframe);
- container.insert(iframe);
- },
-
- // r = ViewPort row data
- msgWindow: function(r)
- {
- this.updateSeenUID(r, 1);
- var url = DIMP.conf.URI_MESSAGE;
- url += (url.include('?') ? '&' : '?') +
- $H({ folder: r.view,
- uid: Number(r.imapuid) }).toQueryString();
- DimpCore.popupWindow(url, 'msgview' + r.view + r.imapuid);
- },
-
- composeMailbox: function(type)
- {
- var sel = this.viewport.getSelected();
- if (!sel.size()) {
- return;
- }
- sel.get('dataob').each(function(s) {
- DimpCore.compose(type, { folder: s.view, uid: s.imapuid });
- });
- },
-
- loadMailbox: function(f, opts)
- {
- opts = opts || {};
-
- if (!this.viewport) {
- this._createViewPort();
- }
-
- if (!opts.background) {
- this.resetSelected();
- this.quicksearchClear(true);
-
- if (this.folder == f) {
- return;
- }
-
- $('folderName').update(DIMP.text.loading);
- $('msgHeader').update();
- this.folderswitch = true;
- this.folder = f;
- }
-
- this.viewport.loadView(f, this.uid ? { imapuid: Number(this.uid), view: f } : null, opts.background);
- },
-
- _createViewPort: function()
- {
- this.viewport = new ViewPort({
- // Mandatory config
- ajax_url: DIMP.conf.URI_AJAX + '/ViewPort',
- content: 'msgList',
- template: this.message_list_template,
-
- // Optional config
- ajax_opts: DimpCore.doActionOpts,
- buffer_pages: DIMP.conf.buffer_pages,
- content_class: 'msglist',
- empty_msg: DIMP.text.vp_empty,
- limit_factor: DIMP.conf.limit_factor,
- page_size: DIMP.conf.splitbar_pos,
- show_split_pane: DIMP.conf.preview_pref,
- split_bar: 'splitBar',
- split_pane: 'previewPane',
- wait: DIMP.conf.viewport_wait,
-
- // Callbacks
- onAjaxRequest: function(id) {
- var p = this.isSearch(id)
- ? $H({
- qsearch: $F('qsearch_input'),
- qsearchmbox: this.sfolder
- })
- : $H();
- return DimpCore.addRequestParams(p);
- }.bind(this),
- onAjaxResponse: DimpCore.doActionComplete.bind(DimpCore),
- onCachedList: function(id) {
- var tmp, vs;
- if (!this.cacheids[id]) {
- vs = this.viewport.getSelection(id);
- if (!vs.size()) {
- return '';
- }
-
- if (vs.getBuffer().getMetaData('search')) {
- this.cacheids[id] = vs.get('uid').toJSON();
- } else {
- tmp = {};
- tmp[id] = vs.get('uid').clone();
- this.cacheids[id] = DimpCore.toRangeString(tmp);
- }
- }
- return this.cacheids[id];
- }.bind(this),
- onCacheUpdate: function(id) {
- delete this.cacheids[id];
- }.bind(this),
- onClear: function(r) {
- r.each(this._removeMouseEvents.bind(this));
- }.bind(this),
- onContent: function(row) {
- var bg, re, u,
- thread = $H(this.viewport.getMetaData('thread')),
- tsort = (this.viewport.getMetaData('sortby') == DIMP.conf.sortthread);
-
- row.subjectdata = row.status = '';
- row.subjecttitle = row.subject;
-
- // Add thread graphics
- if (tsort) {
- u = thread.get(row.imapuid);
- if (u) {
- $R(0, u.length, true).each(function(i) {
- var c = u.charAt(i);
- if (!this.tcache[c]) {
- this.tcache[c] = '<span class="threadImg threadImg' + c + '"></span>';
- }
- row.subjectdata += this.tcache[c];
- }, this);
- }
- }
-
- /* Generate the status flags. */
- if (row.flag) {
- row.flag.each(function(a) {
- var ptr = DIMP.conf.flags[a];
- if (ptr.p) {
- if (!ptr.elt) {
- /* Until text-overflow is supported on all
- * browsers, need to truncate label text
- * ourselves. */
- ptr.elt = '<span class="' + ptr.c + '" title="' + ptr.l + '" style="background:' + ptr.b + '">' + ptr.l.truncate(10) + '</span>';
- }
- row.subjectdata += ptr.elt;
- } else {
- if (!ptr.elt) {
- ptr.elt = '<div class="msgflags ' + ptr.c + '" title="' + ptr.l + '"></div>';
- }
- row.status += ptr.elt;
-
- row.bg.push(ptr.c);
-
- if (ptr.b) {
- bg = ptr.b;
- }
- }
- });
- }
-
- // Set bg
- if (bg) {
- row.style = 'background:' + bg;
- }
-
- // Check for search strings
- if (this.isSearch()) {
- re = new RegExp("(" + $F('qsearch_input') + ")", "i");
- [ 'from', 'subject' ].each(function(h) {
- row[h] = row[h].gsub(re, '<span class="qsearchMatch">#{1}</span>');
- });
- }
-
- // If these fields are null, invalid string was scrubbed by
- // JSON encode.
- if (row.from === null) {
- row.from = '[' + DIMP.text.badaddr + ']';
- }
- if (row.subject === null) {
- row.subject = row.subjecttitle = '[' + DIMP.text.badsubject + ']';
- }
- }.bind(this),
- onContentComplete: function(rows) {
- var row, ssc, tmp,
- l = this.viewport.getMetaData('label');
-
- this.setMessageListTitle();
- if (!this.isSearch()) {
- this.setFolderLabel(this.folder, this.viewport.getMetaData('unseen') || 0);
- }
- this.updateTitle();
-
- rows.each(function(row) {
- // Add context menu
- this._addMouseEvents({ id: row.domid, type: row.menutype });
- new Drag(row.domid, this._msgDragConfig);
- }, this);
-
- if (this.uid) {
- row = this.viewport.getSelection().search({ imapuid: { equal: [ this.uid ] }, view: { equal: [ this.folder ] } });
- if (row.size()) {
- this.viewport.scrollTo(row.get('rownum').first());
- this.viewport.select(row);
- }
- } else if (this.offset) {
- this.viewport.select(this.viewport.createSelection('rownum', this.offset));
- }
- this.offset = this.uid = null;
-
- // 'label' will not be set if there has been an error
- // retrieving data from the server.
- l = this.viewport.getMetaData('label');
- if (l) {
- if (this.isSearch()) {
- l += ' (' + this.sfolder + ')';
- }
- $('folderName').update(l);
- }
-
- if (this.folderswitch) {
- this.folderswitch = false;
-
- tmp = $('applyfilterlink');
- if (tmp) {
- if (this.isSearch() ||
- (!DIMP.conf.filter_any &&
- this.folder.toUpperCase() != 'INBOX')) {
- tmp.hide();
- } else {
- tmp.show();
- }
- }
-
- if (this.folder == DIMP.conf.spam_mbox) {
- if (!DIMP.conf.spam_spammbox && $('button_spam')) {
- [ $('button_spam').up(), $('ctx_message_spam') ].invoke('hide');
- }
- if ($('button_ham')) {
- [ $('button_ham').up(), $('ctx_message_ham') ].invoke('show');
- }
- } else {
- if ($('button_spam')) {
- [ $('button_spam').up(), $('ctx_message_spam') ].invoke('show');
- }
- if ($('button_ham')) {
- [ $('button_ham').up(), $('ctx_message_ham') ].invoke(DIMP.conf.ham_spammbox ? 'hide' : 'show');
- }
- }
-
- /* Read-only changes. 'oa_setflag' is handled
- * elsewhere. */
- tmp = [ $('button_deleted') ].compact().invoke('up', 'SPAN');
- [ 'ctx_message_', 'ctx_draft_' ].each(function(c) {
- tmp = tmp.concat($(c + 'deleted', c + 'setflag', c + 'undeleted'));
- });
-
- if (this.viewport.getMetaData('readonly')) {
- tmp.compact().invoke('hide');
- $('folderName').next().show();
- } else {
- tmp.compact().invoke('show');
- $('folderName').next().hide();
- }
- } else if (this.filtertoggle &&
- this.viewport.getMetaData('sortby') == DIMP.conf.sortthread) {
- ssc = DIMP.conf.sortdate;
- }
-
- this.setSortColumns(ssc);
- }.bind(this),
- onDeselect: this._deselect.bind(this),
- onEndFetch: this.loadingImg.bind(this, 'viewport', false),
- onFail: function() {
- if ($('dimpmain_folder').visible()) {
- DimpCore.showNotifications([ { type: 'horde.error', message: DIMP.text.listmsg_timeout } ]);
- }
- this.loadingImg('viewport', false);
- }.bind(this),
- onFetch: this.loadingImg.bind(this, 'viewport', true),
- onSelect: this._select.bind(this),
- onSlide: this.setMessageListTitle.bind(this),
- onSplitBarChange: function() {
- this._updatePrefs('dimp_splitbar', this.viewport.getPageSize());
- }.bind(this),
- onWait: function() {
- if ($('dimpmain_folder').visible()) {
- DimpCore.showNotifications([ { type: 'horde.warning', message: DIMP.text.listmsg_wait } ]);
- }
- }
- });
-
- // If starting in no preview mode, need to set the no preview class
- if (!DIMP.conf.preview_pref) {
- $('msgList').addClassName('msglistNoPreview');
- }
- },
-
- _addMouseEvents: function(p, popdown)
- {
- if (popdown) {
- popdown.insert({ after: new Element('SPAN', { className: 'iconImg popdownImg popdown', id: p.id + '_img' }) });
- p.id += '_img';
- p.offset = popdown.up();
- p.left = true;
- }
-
- DimpCore.DMenu.addElement(p.id, 'ctx_' + p.type, p);
- },
-
- _removeMouseEvents: function(elt)
- {
- var d, id = $(elt).readAttribute('id');
-
- if (id) {
- if (d = DragDrop.Drags.getDrag(id)) {
- d.destroy();
- }
-
- DimpCore.DMenu.removeElement(id);
- }
- },
-
- contextOnClick: function(parentfunc, elt, baseelt, menu)
- {
- var flag, id = elt.readAttribute('id');
-
- switch (id) {
- case 'ctx_folder_create':
- this.createSubFolder(baseelt);
- break;
-
- case 'ctx_container_rename':
- case 'ctx_folder_rename':
- this.renameFolder(baseelt);
- break;
-
- case 'ctx_folder_empty':
- mbox = baseelt.up('LI').readAttribute('mbox');
- if (window.confirm(DIMP.text.empty_folder.replace(/%s/, mbox))) {
- DimpCore.doAction('EmptyFolder', { view: mbox }, null, this._emptyFolderCallback.bind(this));
- }
- break;
-
- case 'ctx_folder_delete':
- mbox = baseelt.up('LI').readAttribute('title');
- if (window.confirm(DIMP.text.delete_folder.replace(/%s/, mbox))) {
- DimpCore.doAction('DeleteFolder', { view: mbox }, null, this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this)));
- }
- break;
-
- case 'ctx_folder_seen':
- case 'ctx_folder_unseen':
- this.flagAll('\\seen', id == 'ctx_folder_seen', baseelt.up('LI').readAttribute('mbox'));
- break;
-
- case 'ctx_folder_poll':
- case 'ctx_folder_nopoll':
- this.modifyPoll(baseelt.up('LI').readAttribute('mbox'), id == 'ctx_folder_poll');
- break;
-
- case 'ctx_folder_sub':
- case 'ctx_folder_unsub':
- this.subscribeFolder(baseelt.up('LI').readAttribute('mbox'), id == 'ctx_folder_sub');
- break;
-
- case 'ctx_container_create':
- this.createSubFolder(baseelt);
- break;
-
- case 'ctx_folderopts_new':
- this.createBaseFolder();
- break;
-
- case 'ctx_folderopts_sub':
- case 'ctx_folderopts_unsub':
- this.toggleSubscribed();
- break;
-
- case 'ctx_folderopts_expand':
- case 'ctx_folderopts_collapse':
- $('normalfolders').select('LI.folder').each(function(f) {
- this._toggleSubFolder(f, id == 'ctx_folderopts_expand' ? 'exp' : 'col', true);
- }.bind(this));
- break;
-
- case 'ctx_message_spam':
- case 'ctx_message_ham':
- this.reportSpam(id == 'ctx_message_spam');
- break;
-
- case 'ctx_message_blacklist':
- case 'ctx_message_whitelist':
- this.blacklist(id == 'ctx_message_blacklist');
- break;
-
- case 'ctx_draft_deleted':
- case 'ctx_message_deleted':
- this.deleteMsg();
- break;
-
- case 'ctx_message_forward':
- this.composeMailbox('forward');
- break;
-
- case 'ctx_draft_resume':
- this.composeMailbox('resume');
- break;
-
- case 'ctx_reply_reply':
- case 'ctx_reply_reply_all':
- case 'ctx_reply_reply_list':
- this.composeMailbox(id.substring(10));
- break;
-
- case 'previewtoggle':
- this.togglePreviewPane();
- break;
-
- case 'oa_blacklist':
- case 'oa_whitelist':
- this.blacklist(id == 'oa_blacklist');
- break;
-
- case 'ctx_draft_undeleted':
- case 'ctx_message_undeleted':
- case 'oa_undeleted':
- this.flag('\\deleted', false);
-
- case 'oa_selectall':
- this.selectAll();
- break;
-
- case 'oa_purge_deleted':
- this.purgeDeleted();
- break;
-
- case 'ctx_qsearchopts_basic':
- alert('Placeholder for basic search');
- break;
-
- case 'ctx_qsearchopts_advanced':
- alert('Placeholder for advanced search');
- break;
-
- case 'ctx_qsearchopts_all':
- case 'ctx_qsearchopts_body':
- case 'ctx_qsearchopts_from':
- case 'ctx_qsearchopts_subject':
- DIMP.conf.qsearchfield = id.substring(16);
- this._updatePrefs('dimp_qsearch_field', DIMP.conf.qsearchfield);
- break;
-
- default:
- if (menu.endsWith('_setflag') || menu.endsWith('_unsetflag')) {
- flag = elt.readAttribute('flag');
- this.flag(flag, this.convertFlag(flag, menu.endsWith('_setflag')));
- } else {
- parentfunc(elt, baseelt, menu);
- }
- break;
- }
- },
-
- contextOnShow: function(parentfunc, ctx_id, baseelt)
- {
- var elts, ob, sel, tmp;
-
- switch (ctx_id) {
- case 'ctx_folder':
- elts = $('ctx_folder_create', 'ctx_folder_rename', 'ctx_folder_delete');
- baseelt = baseelt.up('LI');
-
- if (baseelt.readAttribute('mbox') == 'INBOX') {
- elts.invoke('hide');
- if ($('ctx_folder_sub')) {
- $('ctx_folder_sub', 'ctx_folder_unsub').invoke('hide');
- }
- } else {
- if ($('ctx_folder_sub')) {
- tmp = baseelt.hasClassName('unsubFolder');
- [ $('ctx_folder_sub') ].invoke(tmp ? 'show' : 'hide');
- [ $('ctx_folder_unsub') ].invoke(tmp ? 'hide' : 'show');
- }
-
- if (DIMP.conf.fixed_folders &&
- DIMP.conf.fixed_folders.indexOf(baseelt.readAttribute('mbox')) != -1) {
- elts.shift();
- elts.invoke('hide');
- } else {
- elts.invoke('show');
- }
- }
-
- tmp = baseelt.hasAttribute('u');
- [ $('ctx_folder_poll') ].invoke(tmp ? 'hide' : 'show');
- [ $('ctx_folder_nopoll') ].invoke(tmp ? 'show' : 'hide');
- break;
-
- case 'ctx_reply':
- sel = this.viewport.getSelected();
- if (sel.size() == 1) {
- ob = sel.get('dataob').first();
- }
- [ $('ctx_reply_reply_list') ].invoke(ob && ob.listmsg ? 'show' : 'hide');
- break;
-
- case 'ctx_otheractions':
- tmp = $('oa_blacklist', 'oa_whitelist', 'oa_undeleted');
- if (this.viewport.getMetaData('readonly')) {
- $('oa_setflag', 'oa_unsetflag').invoke('hide');
- } else {
- tmp = tmp.concat($('oa_setflag', 'oa_unsetflag'));
- }
- tmp.compact().invoke(this.viewport.getSelected().size() ? 'show' : 'hide');
- break;
-
- case 'ctx_qsearchopts':
- $(ctx_id).descendants().invoke('removeClassName', 'contextSelected');
- $(ctx_id + '_' + DIMP.conf.qsearchfield).addClassName('contextSelected');
- break;
-
- default:
- parentfunc(ctx_id, baseelt);
- break;
- }
- },
-
- updateTitle: function()
- {
- var elt, unseen,
- label = this.viewport.getMetaData('label');
-
- if (this.isSearch()) {
- label += ' (' + this.sfolder + ')';
- } else {
- elt = $(this.getFolderId(this.folder));
- if (elt) {
- unseen = elt.readAttribute('u');
- if (unseen > 0) {
- label += ' (' + unseen + ')';
- }
- }
- }
- DimpCore.setTitle(label);
- },
-
- sort: function(e)
- {
- // Don't change sort if we are past the sortlimit
- if (this.viewport.getMetaData('sortlimit')) {
- return;
- }
-
- var s, sortby,
- elt = e.element();
-
- if (!elt.hasAttribute('sortby')) {
- elt = elt.up('[sortby]');
- if (!elt) {
- return;
- }
- }
- sortby = Number(elt.readAttribute('sortby'));
-
- if (sortby == this.viewport.getMetaData('sortby')) {
- s = { sortdir: (this.viewport.getMetaData('sortdir') ? 0 : 1) };
- this.viewport.setMetaData({ sortdir: s.sortdir });
- } else {
- s = { sortby: sortby };
- this.viewport.setMetaData({ sortby: s.sortby });
- }
- this.setSortColumns(sortby);
- this.viewport.reload(s);
- },
-
- setSortColumns: function(sortby)
- {
- var tmp,
- m = $('msglistHeader');
-
- if (Object.isUndefined(sortby)) {
- sortby = this.viewport.getMetaData('sortby');
- }
-
- tmp = m.down('small[sortby=' + sortby + ']');
- if (tmp && tmp.up().visible()) {
- tmp.up(1).childElements().invoke('toggle');
- }
-
- tmp = m.down('div.msgFrom a');
- if (this.viewport.getMetaData('special')) {
- tmp.hide().next().show();
- } else {
- tmp.show().next().hide();
- }
-
- tmp = m.down('div.msgSubject a');
- if (this.isSearch() ||
- this.viewport.getMetaData('nothread') ||
- this.viewport.getMetaData('sortlimit')) {
- tmp.show().next().hide();
- tmp.down().hide();
- } else {
- tmp.down().show();
- }
-
- m.childElements().invoke('removeClassName', 'sortup').invoke('removeClassName', 'sortdown');
-
- tmp = m.down('div a[sortby=' + sortby + ']');
- if (tmp) {
- tmp.up().addClassName(this.viewport.getMetaData('sortdir') ? 'sortup' : 'sortdown');
- }
- },
-
- // Preview pane functions
- togglePreviewPane: function()
- {
- var p = DIMP.conf.preview_pref = !DIMP.conf.preview_pref;
- $('previewtoggle').setText(p ? DIMP.text.hide_preview : DIMP.text.show_preview);
- [ $('msgList') ].invoke(p ? 'removeClassName' : 'addClassName', 'msglistNoPreview');
- this._updatePrefs('show_preview', Number(p));
- this.viewport.showSplitPane(p);
- if (p) {
- this.initPreviewPane();
- }
- },
-
- loadPreview: function(data, params)
- {
- var pp_uid;
-
- if (!$('previewPane').visible()) {
- return;
- }
-
- if (!params) {
- if (this.pp &&
- this.pp.imapuid == data.imapuid &&
- this.pp.view == data.view) {
- return;
- }
- this.pp = data;
- pp_uid = this._getPPId(data.imapuid, data.view);
-
- if (this.ppfifo.indexOf(pp_uid) != -1) {
- // There is a chance that the message may have been marked
- // as unseen since first being viewed. If so, we need to
- // explicitly flag as seen here.
- if (!this.hasFlag('\\seen', data)) {
- this.flag('\\seen', true);
- }
- return this._loadPreviewCallback(this.ppcache[pp_uid]);
- }
- }
-
- this.loadingImg('msg', true);
-
- DimpCore.doAction('ShowPreview', params || {}, this.viewport.createSelection('dataob', this.pp), this.bcache.get('loadPC') || this.bcache.set('loadPC', this._loadPreviewCallback.bind(this)));
- },
-
- _loadPreviewCallback: function(resp)
- {
- var ppuid, row, search, tmp,
- pm = $('previewMsg'),
- r = resp.response,
- t = $('msgHeadersContent').down('THEAD');
-
- if (!r.error) {
- search = this.viewport.getSelection().search({ imapuid: { equal: [ r.index ] }, view: { equal: [ r.mailbox ] } });
- if (search.size()) {
- row = search.get('dataob').first();
- this.updateSeenUID(row, 1);
- }
- }
-
- if (this.pp &&
- (this.pp.imapuid != r.index ||
- this.pp.view != r.mailbox)) {
- return;
- }
-
- if (r.error || this.viewport.getSelected().size() != 1) {
- if (r.error) {
- DimpCore.showNotifications([ { type: r.errortype, message: r.error } ]);
- }
- this.clearPreviewPane();
- return;
- }
-
- // Store in cache.
- ppuid = this._getPPId(r.index, r.mailbox);
- this._expirePPCache([ ppuid ]);
- this.ppcache[ppuid] = resp;
- this.ppfifo.push(ppuid);
-
- DimpCore.removeAddressLinks(pm);
-
- // Add subject
- tmp = pm.select('.subject');
- tmp.invoke('update', r.subject === null ? '[' + DIMP.text.badsubject + ']' : r.subject);
-
- // Add date
- $('msgHeadersColl').select('.date').invoke('update', r.minidate);
- $('msgHeaderDate').select('.date').invoke('update', r.localdate);
-
- // Add from/to/cc headers
- [ 'from', 'to', 'cc' ].each(function(a) {
- if (r[a]) {
- (a == 'from' ? pm.select('.' + a) : [ t.down('.' + a) ]).each(function(elt) {
- elt.replace(DimpCore.buildAddressLinks(r[a], elt.cloneNode(false)));
- });
- }
- [ $('msgHeader' + a.capitalize()) ].invoke(r[a] ? 'show' : 'hide');
- });
-
- // Add attachment information
- if (r.atc_label) {
- $('msgAtc').show();
- tmp = $('partlist');
- tmp.hide().previous().update(new Element('SPAN', { className: 'atcLabel' }).insert(r.atc_label)).insert(r.atc_download);
- if (r.atc_list) {
- $('partlist_col').show();
- $('partlist_exp').hide();
- tmp.down('TABLE').update(r.atc_list);
- }
- } else {
- $('msgAtc').hide();
- }
-
- // Add message information
- if (r.log) {
- this.updateMsgLog(r.log);
- } else {
- $('msgLogInfo').hide();
- }
-
- $('msgBody').update(r.msgtext);
- this.loadingImg('msg', false);
- $('previewInfo').hide();
- $('previewPane').scrollTop = 0;
- pm.show();
-
- if (r.js) {
- eval(r.js.join(';'));
- }
-
- this._addHistory('msg:' + row.view + ':' + row.imapuid);
- },
-
- // opts = index, mailbox
- updateMsgLog: function(log, opts)
- {
- var tmp;
-
- if (!opts ||
- (this.pp.imapuid == opts.index &&
- this.pp.view == opts.mailbox)) {
- $('msgLogInfo').show();
-
- if (opts) {
- $('msgloglist_col').show();
- $('msgloglist_exp').hide();
- }
-
- DimpCore.updateMsgLog(log);
- }
-
- if (opts) {
- tmp = this._getPPId(opts.index, opts.mailbox);
- if (this.ppcache[tmp]) {
- this.ppcache[tmp].response.log = log;
- }
- }
- },
-
- initPreviewPane: function()
- {
- var sel = this.viewport.getSelected();
- if (sel.size() != 1) {
- this.clearPreviewPane();
- } else {
- this.loadPreview(sel.get('dataob').first());
- }
- },
-
- clearPreviewPane: function()
- {
- this.loadingImg('msg', false);
- $('previewMsg').hide();
- $('previewPane').scrollTop = 0;
- $('previewInfo').show();
- this.pp = null;
- },
-
- _toggleHeaders: function(elt, update)
- {
- if (update) {
- DIMP.conf.toggle_pref = !DIMP.conf.toggle_pref;
- this._updatePrefs('dimp_toggle_headers', Number(elt.id == 'th_expand'));
- }
- [ elt.up().select('A'), $('msgHeadersColl', 'msgHeaders') ].flatten().invoke('toggle');
- },
-
- _expirePPCache: function(ids)
- {
- this.ppfifo = this.ppfifo.diff(ids);
- ids.each(function(i) {
- delete this.ppcache[i];
- }, this);
-
- if (this.ppfifo.size() > this.ppcachesize) {
- delete this.ppcache[this.ppfifo.shift()];
- }
- },
-
- _getPPId: function(index, mailbox)
- {
- return index + '|' + mailbox;
- },
-
- // Labeling functions
- updateSeenUID: function(r, setflag)
- {
- var isunseen = !this.hasFlag('\\seen', r),
- sel, unseen;
-
- if ((setflag && !isunseen) || (!setflag && isunseen)) {
- return false;
- }
-
- sel = this.viewport.createSelection('dataob', r);
- unseen = Number($(this.getFolderId(r.view)).readAttribute('u'));
-
- unseen += setflag ? -1 : 1;
- this.updateFlag(sel, '\\seen', setflag);
-
- this.updateUnseenStatus(r.view, unseen);
- },
-
- updateUnseenStatus: function(mbox, unseen)
- {
- if (this.viewport) {
- this.viewport.setMetaData({ unseen: unseen }, mbox);
- }
-
- this.setFolderLabel(mbox, unseen);
-
- if (this.folder == mbox) {
- this.updateTitle();
- }
- },
-
- setMessageListTitle: function()
- {
- var offset,
- rows = this.viewport.getMetaData('total_rows');
-
- if (rows > 0) {
- offset = this.viewport.currentOffset();
- $('msgHeader').update(DIMP.text.messages + ' ' + (offset + 1) + ' - ' + (Math.min(offset + this.viewport.getPageSize(), rows)) + ' ' + DIMP.text.of + ' ' + rows);
- } else {
- $('msgHeader').update(DIMP.text.nomessages);
- }
- },
-
- setFolderLabel: function(f, unseen)
- {
- var fid = this.getFolderId(f),
- elt = $(fid);
-
- if (!elt ||
- !elt.hasAttribute('u') ||
- elt.readAttribute('u') == unseen) {
- return;
- }
-
- unseen = Number(unseen);
- elt.writeAttribute('u', unseen);
-
- if (f == 'INBOX' && window.fluid) {
- window.fluid.setDockBadge(unseen ? unseen : '');
- }
-
- $(fid).down('A').update((unseen > 0) ?
- new Element('STRONG').insert(elt.readAttribute('l')).insert(' ').insert(new Element('SPAN', { className: 'count', dir: 'ltr' }).insert('(' + unseen + ')')) :
- elt.readAttribute('l'));
- },
-
- getFolderId: function(f)
- {
- return 'fld' + f.replace(/_/g,'__').replace(/\W/g, '_');
- },
-
- getSubFolderId: function(f)
- {
- return 'sub' + f;
- },
-
- /* Folder list updates. */
- poll: function()
- {
- var args = {};
-
- // Reset poll folder counter.
- this.setPoll();
-
- // Check for label info - it is possible that the mailbox may be
- // loading but not complete yet and sending this request will cause
- // duplicate info to be returned.
- if (this.folder &&
- $('dimpmain_folder').visible() &&
- this.viewport.getMetaData('label')) {
- args = this.viewport.addRequestParams({});
- }
- $('checkmaillink').down('A').update('[' + DIMP.text.check + ']');
- DimpCore.doAction('Poll', args, null, this.bcache.get('pollFC') || this.bcache.set('pollFC', this._pollCallback.bind(this)));
- },
-
- _pollCallback: function(r)
- {
- r = r.response;
- if (r.poll) {
- $H(r.poll).each(function(u) {
- this.updateUnseenStatus(u.key, u.value);
- }, this);
- }
- if (r.quota) {
- this._displayQuota(r.quota);
- }
- $('checkmaillink').down('A').update(DIMP.text.getmail);
- },
-
- _displayQuota: function(r)
- {
- var q = $('quota').cleanWhitespace();
- q.setText(r.m);
- q.down('SPAN.used IMG').writeAttribute({ width: 99 - r.p });
- },
-
- setPoll: function()
- {
- if (DIMP.conf.refresh_time) {
- if (this.pollPE) {
- this.pollPE.stop();
- }
- // Don't cache - this code is only run once.
- this.pollPE = new PeriodicalExecuter(this.poll.bind(this), DIMP.conf.refresh_time);
- }
- },
-
- _portalCallback: function(r)
- {
- if (r.response.linkTags) {
- var head = $(document.documentElement).down('HEAD');
- r.response.linkTags.each(function(newLink) {
- var link = new Element('LINK', { type: 'text/css', rel: 'stylesheet', href: newLink.href });
- if (newLink.media) {
- link.media = newLink.media;
- }
- head.insert(link);
- });
- }
- $('dimpmain_portal').update(r.response.portal);
- },
-
- /* Search functions. */
- isSearch: function(id)
- {
- return (id ? id : this.folder) == DIMP.conf.qsearchid;
- },
-
- _quicksearchOnBlur: function()
- {
- $('qsearch').removeClassName('qsearchFocus');
- if (!$F('qsearch_input')) {
- this._setFilterText(true);
- }
- },
-
- quicksearchRun: function()
- {
- if (this.isSearch()) {
- this.viewport.reload();
- } else {
- this.sfolder = this.folder;
- $('qsearch_close').show();
- this.loadMailbox(DIMP.conf.qsearchid);
- }
- },
-
- // 'noload' = (boolean) If true, don't load the mailbox
- quicksearchClear: function(noload)
- {
- if (this.isSearch()) {
- $('qsearch_close').hide();
- if (!$('qsearch').hasClassName('qsearchFocus')) {
- this._setFilterText(true);
- }
- this.resetSelected();
- if (!noload) {
- this.loadMailbox(this.sfolder);
- }
- this.viewport.deleteView(DIMP.conf.qsearchid);
- }
- },
-
- // d = (boolean) Deactivate filter input?
- _setFilterText: function(d)
- {
- $('qsearch_input').setValue(d ? DIMP.text.search : '');
- [ $('qsearch') ].invoke(d ? 'removeClassName' : 'addClassName', 'qsearchActive');
- },
-
- /* Enable/Disable DIMP action buttons as needed. */
- toggleButtons: function()
- {
- var disable = (this.selectedCount() == 0);
- $('dimpmain_folder_top').select('DIV.dimpActions A.noselectDisable').each(function(b) {
- [ b.up() ].invoke(disable ? 'addClassName' : 'removeClassName', 'disabled');
- DimpCore.DMenu.disable(b.readAttribute('id') + '_img', true, disable);
- });
- },
-
- /* Drag/Drop handler. */
- _folderDropHandler: function(drop, drag, e)
- {
- var dropbase, sel, uids,
- foldername = drop.readAttribute('mbox'),
- ftype = drop.readAttribute('ftype');
-
- if (drag.hasClassName('folder')) {
- dropbase = (drop == $('dropbase'));
- if (dropbase ||
- (ftype != 'special' && !this.isSubfolder(drag, drop))) {
- DimpCore.doAction('RenameFolder', { old_name: drag.readAttribute('mbox'), new_parent: dropbase ? '' : foldername, new_name: drag.readAttribute('l') }, null, this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this)));
- }
- } else if (ftype != 'container') {
- sel = this.viewport.getSelected();
-
- if (sel.size()) {
- // Dragging multiple selected messages.
- uids = sel;
- } else if (drag.readAttribute('mbox') != foldername) {
- // Dragging a single unselected message.
- uids = this.viewport.createSelection('domid', drag.id);
- }
-
- if (uids.size()) {
- if (e.ctrlKey) {
- DimpCore.doAction('CopyMessage', this.viewport.addRequestParams({ tofld: foldername }), uids, this.bcache.get('pollFC') || this.bcache.set('pollFC', this._pollCallback.bind(this)));
- } else if (this.folder != foldername) {
- // Don't allow drag/drop to the current folder.
- this.updateFlag(uids, '\\deleted', true);
- DimpCore.doAction('MoveMessage', this.viewport.addRequestParams({ tofld: foldername }), uids, this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)));
- }
- }
- }
- },
-
- dragCaption: function()
- {
- var cnt = this.selectedCount();
- return cnt + ' ' + (cnt == 1 ? DIMP.text.message : DIMP.text.messages);
- },
-
- /* Keydown event handler */
- keydownHandler: function(e)
- {
- var co, form, h, pp, ps, r, row, rowoff, sel,
- elt = e.element(),
- kc = e.keyCode || e.charCode;
-
- // Only catch keyboard shortcuts in message list view.
- if (!$('dimpmain_folder').visible()) {
- return;
- }
-
- // Form catching - normally we will ignore, but certain cases we want
- // to catch.
- form = e.findElement('FORM');
- if (form) {
- switch (kc) {
- case Event.KEY_ESC:
- case Event.KEY_TAB:
- // Catch escapes in search box
- if (elt.readAttribute('id') == 'qsearch_input') {
- if (kc == Event.KEY_ESC || !elt.getValue()) {
- this.quicksearchClear();
- }
- elt.blur();
- e.stop();
- }
- break;
-
- case Event.KEY_RETURN:
- // Catch returns in RedBox
- if (form.readAttribute('id') == 'RB_folder') {
- this.cfolderaction(e);
- e.stop();
- } else if (elt.readAttribute('id') == 'qsearch_input') {
- if ($F('qsearch_input')) {
- this.quicksearchRun();
- } else {
- this.quicksearchClear();
- }
- e.stop();
- }
- break;
- }
-
- return;
- }
-
- sel = this.viewport.getSelected();
-
- switch (kc) {
- case Event.KEY_DELETE:
- case Event.KEY_BACKSPACE:
- r = sel.get('dataob');
- if (e.shiftKey) {
- this.moveSelected((r.last().rownum == this.viewport.getMetaData('total_rows')) ? (r.first().rownum - 1) : (r.last().rownum + 1), true);
- }
- this.deleteMsg({ vs: sel });
- e.stop();
- break;
-
- case Event.KEY_UP:
- case Event.KEY_DOWN:
- if (e.shiftKey && this.lastrow != -1) {
- row = this.viewport.createSelection('rownum', this.lastrow + ((kc == Event.KEY_UP) ? -1 : 1));
- if (row.size()) {
- row = row.get('dataob').first();
- this.viewport.scrollTo(row.rownum);
- this.msgSelect(row.domid, { shift: true });
- }
- } else {
- this.moveSelected(kc == Event.KEY_UP ? -1 : 1);
- }
- e.stop();
- break;
-
- case Event.KEY_PAGEUP:
- case Event.KEY_PAGEDOWN:
- if (e.altKey) {
- pp = $('previewPane');
- h = pp.getHeight();
- if (h != pp.scrollHeight) {
- switch (kc) {
- case Event.KEY_PAGEUP:
- pp.scrollTop = Math.max(pp.scrollTop - h, 0);
- break;
-
- case Event.KEY_PAGEDOWN:
- pp.scrollTop = Math.min(pp.scrollTop + h, pp.scrollHeight - h + 1);
- break;
- }
- }
- e.stop();
- } else if (!e.ctrlKey && !e.shiftKey && !e.metaKey) {
- ps = this.viewport.getPageSize() - 1;
- move = ps * (kc == Event.KEY_PAGEUP ? -1 : 1);
- if (sel.size() == 1) {
- co = this.viewport.currentOffset();
- rowoff = sel.get('rownum').first() - 1;
- switch (kc) {
- case Event.KEY_PAGEUP:
- if (co != rowoff) {
- move = co - rowoff;
- }
- break;
-
- case Event.KEY_PAGEDOWN:
- if ((co + ps) != rowoff) {
- move = co + ps - rowoff;
- }
- break;
- }
- }
- this.moveSelected(move);
- e.stop();
- }
- break;
-
- case Event.KEY_HOME:
- case Event.KEY_END:
- this.moveSelected(kc == Event.KEY_HOME ? 1 : this.viewport.getMetaData('total_rows'), true);
- e.stop();
- break;
-
- case Event.KEY_RETURN:
- if (!elt.match('input')) {
- // Popup message window if single message is selected.
- if (sel.size() == 1) {
- this.msgWindow(sel.get('dataob').first());
- }
- }
- e.stop();
- break;
-
- case 65: // A
- case 97: // a
- if (e.ctrlKey) {
- this.selectAll();
- e.stop();
- }
- break;
- }
- },
-
- dblclickHandler: function(e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = e.element(),
- tmp;
-
- if (!elt.hasClassName('vpRow')) {
- elt = elt.up('.vpRow');
- }
-
- if (elt) {
- tmp = this.viewport.createSelection('domid', elt.identify()).get('dataob').first();
- tmp.draft
- ? DimpCore.compose('resume', { folder: tmp.view, uid: tmp.imapuid })
- : this.msgWindow(tmp);
- }
-
- e.stop();
- },
-
- clickHandler: function(parentfunc, e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = e.element(),
- id, tmp;
-
- while (Object.isElement(elt)) {
- id = elt.readAttribute('id');
-
- switch (id) {
- case 'normalfolders':
- case 'specialfolders':
- this._handleFolderMouseClick(e);
- break;
-
- case 'hometab':
- case 'logolink':
- this.go('portal');
- e.stop();
- return;
-
- case 'button_compose':
- case 'composelink':
- DimpCore.compose('new');
- e.stop();
- return;
-
- case 'checkmaillink':
- this.poll();
- e.stop();
- return;
-
- case 'fetchmaillink':
- IMPDialog.display({ dialog_load: DIMP.conf.URI_AJAX + '/FetchmailDialog' });
- e.stop();
- return;
-
- case 'applyfilterlink':
- if (this.viewport) {
- this.viewport.reload({ applyfilter: 1 });
- }
- e.stop();
- return;
-
- case 'appportal':
- case 'appoptions':
- this.go(id.substring(3));
- e.stop();
- return;
-
- case 'applogout':
- elt.down('A').update('[' + DIMP.text.onlogout + ']');
- DimpCore.logout();
- e.stop();
- return;
-
- case 'folderopts':
- DimpCore.DMenu.trigger($('folderopts_img'), true);
- return;
-
- case 'button_forward':
- case 'button_reply':
- this.composeMailbox(id == 'button_reply' ? 'reply' : 'forward');
- break;
-
- case 'button_ham':
- case 'button_spam':
- this.reportSpam(id == 'button_spam');
- e.stop();
- return;
-
- case 'button_deleted':
- this.deleteMsg();
- e.stop();
- return;
-
- case 'button_other':
- DimpCore.DMenu.trigger(e.findElement('A').next(), true);
- e.stop();
- return;
-
- case 'msglistHeader':
- this.sort(e);
- e.stop();
- return;
-
- case 'th_expand':
- case 'th_collapse':
- this._toggleHeaders(elt, true);
- break;
-
- case 'msgloglist_toggle':
- case 'partlist_toggle':
- tmp = (id == 'partlist_toggle') ? 'partlist' : 'msgloglist';
- $(tmp + '_col', tmp + '_exp').invoke('toggle');
- Effect.toggle(tmp, 'blind', {
- duration: 0.2,
- queue: {
- position: 'end',
- scope: tmp,
- limit: 2
- }
- });
- break;
-
- case 'msg_newwin':
- case 'msg_newwin_options':
- this.msgWindow(this.viewport.getSelection().search({ imapuid: { equal: [ this.pp.imapuid ] } , view: { equal: [ this.pp.view ] } }).get('dataob').first());
- e.stop();
- return;
-
- case 'msg_view_source':
- DimpCore.popupWindow(DimpCore.addURLParam(DIMP.conf.URI_VIEW, { uid: this.pp.imapuid, mailbox: this.pp.view, actionID: 'view_source', id: 0 }, true), DIMP.conf.msg_index + '|' + DIMP.conf.msg_folder);
- break;
-
- case 'applicationfolders':
- tmp = e.element();
- if (!tmp.hasClassName('custom')) {
- tmp = tmp.up('LI.custom');
- }
- if (tmp) {
- this.go('app:' + tmp.down('A').identify().substring(3));
- e.stop();
- return;
- }
- break;
-
- case 'tabbar':
- if (e.element().hasClassName('applicationtab')) {
- this.go('app:' + e.element().identify().substring(6));
- e.stop();
- return;
- }
- break;
-
- case 'dimpmain_portal':
- if (e.element().match('H1.header a')) {
- this.go('app:' + e.element().readAttribute('app'));
- e.stop();
- return;
- }
- break;
-
- case 'qsearch_icon':
- DimpCore.DMenu.trigger($('qsearch_icon'), true);
- e.stop();
- return;
-
- case 'qsearch':
- elt.addClassName('qsearchFocus');
- if (!elt.hasClassName('qsearchActive')) {
- this._setFilterText(false);
- }
- $('qsearch_input').focus();
- break;
-
- case 'qsearch_close':
- this.quicksearchClear();
- e.stop();
- return;
-
- default:
- if (elt.hasClassName('RBFolderOk')) {
- this.cfolderaction(e);
- e.stop();
- return;
- } else if (elt.hasClassName('RBFolderCancel')) {
- this._closeRedBox();
- e.stop();
- return;
- }
- }
-
- elt = elt.up();
- }
-
- parentfunc(e);
- },
-
- mouseoverHandler: function(e)
- {
- if (DragDrop.Drags.drag) {
- var elt = e.element();
- if (elt.hasClassName('exp')) {
- this._toggleSubFolder(elt.up(), 'exp');
- }
- }
- },
-
- /* Handle rename folder actions. */
- renameFolder: function(folder)
- {
- if (Object.isUndefined(folder)) {
- return;
- }
-
- folder = $(folder);
- var n = this._createFolderForm(this._folderAction.bindAsEventListener(this, folder, 'rename'), DIMP.text.rename_prompt);
- n.down('input').setValue(folder.readAttribute('l'));
- },
-
- /* Handle insert folder actions. */
- createBaseFolder: function()
- {
- this._createFolderForm(this._folderAction.bindAsEventListener(this, '', 'create'), DIMP.text.create_prompt);
- },
-
- createSubFolder: function(folder)
- {
- if (!Object.isUndefined(folder)) {
- this._createFolderForm(this._folderAction.bindAsEventListener(this, $(folder), 'createsub'), DIMP.text.createsub_prompt);
- }
- },
-
- _createFolderForm: function(action, text)
- {
- var n = $($('folderform').down().cloneNode(true)).writeAttribute('id', 'RB_folder');
- n.down('P').insert(text);
-
- this.cfolderaction = action;
-
- RedBox.overlay = true;
- RedBox.onDisplay = Form.focusFirstElement.curry(n);
- RedBox.showHtml(n);
- return n;
- },
-
- _closeRedBox: function()
- {
- RedBox.close();
- this.cfolderaction = null;
- },
-
- _folderAction: function(e, folder, mode)
- {
- this._closeRedBox();
-
- var action, params, val,
- form = e.findElement('form');
- val = $F(form.down('input'));
-
- if (val) {
- switch (mode) {
- case 'rename':
- folder = folder.up('LI');
- if (folder.readAttribute('l') != val) {
- action = 'RenameFolder';
- params = { old_name: folder.readAttribute('mbox'),
- new_parent: folder.up().hasClassName('folderlist') ? '' : folder.up(1).previous().readAttribute('mbox'),
- new_name: val };
- }
- break;
-
- case 'create':
- case 'createsub':
- action = 'CreateFolder';
- params = { view: val };
- if (mode == 'createsub') {
- params.parent = folder.up('LI').readAttribute('mbox');
- }
- break;
- }
-
- if (action) {
- DimpCore.doAction(action, params, null, this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this)));
- }
- }
- },
-
- /* Folder action callback functions. */
- _folderCallback: function(r)
- {
- r = r.response;
- if (r.d) {
- r.d.each(this.bcache.get('deleteFolder') || this.bcache.set('deleteFolder', this.deleteFolder.bind(this)));
- }
- if (r.c) {
- r.c.each(this.bcache.get('changeFolder') || this.bcache.set('changeFolder', this.changeFolder.bind(this)));
- }
- if (r.a) {
- r.a.each(this.bcache.get('createFolder') || this.bcache.set('createFolder', this.createFolder.bind(this)));
- }
- },
-
- _deleteCallback: function(r)
- {
- var search = null, uids = [], vs;
-
- this.loadingImg('viewport', false);
- this._pollCallback(r);
-
- r = r.response;
- if (!r.uids || r.folder != this.folder) {
- return;
- }
- r.uids = DimpCore.parseRangeString(r.uids);
-
- // Need to convert uid list to listing of unique viewport IDs since
- // we may be dealing with multiple mailboxes (i.e. virtual folders)
- vs = this.viewport.getSelection(this.folder);
- if (vs.getBuffer().getMetaData('search')) {
- $H(r.uids).each(function(pair) {
- pair.value.each(function(v) {
- uids.push(v + pair.key);
- });
- });
-
- search = this.viewport.getSelection().search({ vp_id: { equal: uids } });
- } else {
- r.uids = r.uids[this.folder];
- r.uids.each(function(f, u) {
- uids.push(u + f);
- }.curry(this.folder));
- search = this.viewport.createSelection('uid', r.uids);
- }
-
- if (search.size()) {
- if (r.remove) {
- // TODO: Don't use cacheid
- this.viewport.remove(search, { cacheid: r.cacheid, noupdate: r.ViewPort });
- this._expirePPCache(uids);
- } else {
- // Need this to catch spam deletions.
- this.updateFlag(search, '\\deleted', true);
- }
- }
- },
-
- _emptyFolderCallback: function(r)
- {
- if (r.response.mbox) {
- if (this.folder == r.response.mbox) {
- this.viewport.reload();
- this.clearPreviewPane();
- }
- this.setFolderLabel(r.response.mbox, 0);
- }
- },
-
- _flagAllCallback: function(r)
- {
- if (r.response) {
- if (r.response.mbox == this.folder) {
- r.response.flags.each(function(f) {
- this.updateFlag(this.viewport.createSelection('rownum', $A($R(1, this.viewport.getMetaData('total_rows')))), f, r.response.set);
- }, this);
- }
- this._pollCallback(r);
- }
- },
-
- _folderLoadCallback: function(r)
- {
- this._folderCallback(r);
-
- var nf = $('normalfolders'),
- nfheight = nf.getStyle('max-height');
-
- if (this.folder) {
- this.highlightSidebar(this.getFolderId(this.folder));
- }
-
- $('foldersLoading').hide();
- $('foldersSidebar').show();
-
- // Fix for IE6 - which doesn't support max-height. We need to search
- // for height: 0px instead (comment in IE 6 CSS explains this is
- // needed for auto sizing).
- if (nfheight !== null ||
- (Prototype.Browser.IE &&
- Object.isUndefined(nfheight) &&
- (nf.getStyle('height') == '0px'))) {
- this._sizeFolderlist();
- Event.observe(window, 'resize', this._sizeFolderlist.bind(this));
- }
-
- if (r.response.quota) {
- this._displayQuota(r.response.quota);
- }
- },
-
- _handleFolderMouseClick: function(e)
- {
- var elt = e.element(),
- li = elt.up('.folder') || elt.up('.custom');
-
- if (!li) {
- return;
- }
-
- if (elt.hasClassName('exp') || elt.hasClassName('col')) {
- this._toggleSubFolder(li, 'tog');
- } else {
- switch (li.readAttribute('ftype')) {
- case 'container':
- case 'vcontainer':
- e.stop();
- break;
-
- case 'folder':
- case 'special':
- case 'virtual':
- e.stop();
- return this.go('folder:' + li.readAttribute('mbox'));
- }
- }
- },
-
- _toggleSubFolder: function(base, mode, noeffect)
- {
- // Make sure all subfolders are expanded.
- // The last 2 elements of ancestors() are the BODY and HTML tags -
- // don't need to parse through them.
- var subs = (mode == 'exp')
- ? base.ancestors().slice(0, -2).reverse().findAll(function(n) { return n.hasClassName('subfolders'); })
- : [ base.next('.subfolders') ];
-
- subs.compact().each(function(s) {
- if (mode == 'tog' ||
- (mode == 'exp' && !s.visible()) ||
- (mode == 'col' && s.visible())) {
- s.previous().down().toggleClassName('exp').toggleClassName('col');
-
- if (noeffect) {
- s.toggle();
- } else {
- Effect.toggle(s, 'blind', {
- duration: 0.2,
- queue: {
- position: 'end',
- scope: 'subfolder'
- }
- });
- }
- }
- }.bind(this));
- },
-
- // Folder actions.
- // For format of the ob object, see DIMP::_createFolderElt().
- createFolder: function(ob)
- {
- var div, f_node, ftype, li, ll, parent_e, tmp,
- cname = 'folder',
- fid = this.getFolderId(ob.m),
- label = ob.l || ob.m,
- mbox = ob.m,
- submboxid = this.getSubFolderId(fid),
- submbox = $(submboxid),
- title = ob.t || ob.m;
-
- if (ob.v) {
- ftype = ob.co ? 'vcontainer' : 'virtual';
- title = label;
- } else if (ob.co) {
- ftype = 'container';
-
- /* This is a dummy container element to display child elements of
- * a mailbox displayed in the 'specialfolders' section. */
- if (ob.s) {
- fid += '_special';
- ob.s = false;
- cname += ' specialContainer';
- }
- } else {
- ftype = ob.s ? 'special' : 'folder';
- }
-
- if (ob.un) {
- cname += ' unsubFolder';
- }
-
- div = new Element('DIV', { className: 'iconDiv' });
- if (ob.i) {
- div.setStyle({ backgroundImage: 'url("' + ob.i + '")' });
- }
-
- li = new Element('LI', { className: cname, id: fid, l: label, mbox: mbox, title: title }).insert(div).insert(new Element('A').insert(label));
-
- // Now walk through the parent <ul> to find the right place to
- // insert the new folder.
- if (submbox) {
- if (submbox.insert({ before: li }).visible()) {
- // If an expanded parent mailbox was deleted, we need to toggle
- // the icon accordingly.
- div.addClassName('col');
- }
- } else {
- div.addClassName(ob.ch ? 'exp' : (ob.cl || 'base'));
-
- if (ob.s) {
- parent_e = $('specialfolders');
-
- /* Create a dummy container element in 'normalfolders'
- * section. */
- if (ob.ch) {
- div.removeClassName('exp').addClassName(ob.cl || 'base');
-
- tmp = Object.clone(ob);
- tmp.co = true;
- this.createFolder(tmp);
- }
- } else {
- parent_e = ob.pa
- ? $(this.getSubFolderId(this.getFolderId(ob.pa))).down()
- : $('normalfolders');
- }
-
- /* Virtual folders are sorted on the server. */
- if (!ob.v) {
- ll = mbox.toLowerCase();
- f_node = parent_e.childElements().find(function(node) {
- var nodembox = node.readAttribute('mbox');
- return nodembox &&
- (!ob.s || nodembox != 'INBOX') &&
- (ll < nodembox.toLowerCase());
- });
- }
-
- if (f_node) {
- f_node.insert({ before: li });
- } else {
- parent_e.insert(li);
- }
-
- // Make sure the sub<mbox> ul is created if necessary.
- if (!ob.s && ob.ch) {
- li.insert({ after: new Element('LI', { className: 'subfolders', id: submboxid }).insert(new Element('UL')).hide() });
- }
- }
-
- li.writeAttribute('ftype', ftype);
-
- // Make the new folder a drop target.
- if (!ob.v) {
- new Drop(li, this._folderDropConfig);
- }
-
- // Check for unseen messages
- if (ob.po) {
- li.writeAttribute('u', '');
- this.setFolderLabel(mbox, ob.u);
- }
-
- switch (ftype) {
- case 'special':
- // For purposes of the contextmenu, treat special folders
- // like regular folders.
- ftype = 'folder';
- // Fall through.
-
- case 'container':
- case 'folder':
- new Drag(li, this._folderDragConfig);
- this._addMouseEvents({ id: fid, type: ftype });
- break;
- }
- },
-
- deleteFolder: function(folder)
- {
- if (this.folder == folder) {
- this.go('folder:INBOX');
- }
- this.deleteFolderElt(this.getFolderId(folder), true);
- },
-
- changeFolder: function(ob)
- {
- var fid = this.getFolderId(ob.m),
- fdiv = $(fid).down('DIV'),
- oldexpand = fdiv && fdiv.hasClassName('col');
- this.deleteFolderElt(fid, !ob.ch);
- if (ob.co && this.folder == ob.m) {
- this.go('folder:INBOX');
- }
- this.createFolder(ob);
- if (ob.ch && oldexpand) {
- fdiv.removeClassName('exp').addClassName('col');
- }
- },
-
- deleteFolderElt: function(fid, sub)
- {
- var f = $(fid), submbox;
- if (!f) {
- return;
- }
-
- if (sub) {
- submbox = $(this.getSubFolderId(fid));
- if (submbox) {
- submbox.remove();
- }
- }
- [ DragDrop.Drags.getDrag(fid), DragDrop.Drops.getDrop(fid) ].compact().invoke('destroy');
- this._removeMouseEvents(f);
- if (this.viewport) {
- this.viewport.deleteView(fid);
- }
- f.remove();
- },
-
- _sizeFolderlist: function()
- {
- var nf = $('normalfolders');
- nf.setStyle({ height: (document.viewport.getHeight() - nf.cumulativeOffset()[1]) + 'px' });
- },
-
- toggleSubscribed: function()
- {
- this.showunsub = !this.showunsub;
- $('foldersLoading').show();
- $('foldersSidebar').hide();
- $('ctx_folderopts_sub', 'ctx_folderopts_unsub').invoke('toggle');
-
- // TODO - Only do for unsub -> sub switch
- [ $('specialfolders').childElements(), $('dropbase').nextSiblings() ].flatten().each(function(elt) {
- this.deleteFolderElt(elt.readAttribute('id'), true);
- }, this);
-
- DimpCore.doAction('ListFolders', { unsub: Number(this.showunsub) }, null, this._folderLoadCallback.bind(this));
- },
-
- subscribeFolder: function(f, sub)
- {
- var fid = this.getFolderId(f);
- DimpCore.doAction('Subscribe', { view: f, sub: Number(sub) });
-
- if (this.showunsub) {
- [ $(fid) ].invoke(sub ? 'removeClassName' : 'addClassName', 'unsubFolder');
- } else if (!sub) {
- this.deleteFolderElt(fid);
- }
- },
-
- /* Flag actions for message list. */
- _getFlagSelection: function(opts)
- {
- var vs;
-
- if (opts.vs) {
- vs = opts.vs;
- } else if (opts.index) {
- if (opts.mailbox) {
- vs = this.viewport.getSelection().search({ imapuid: { equal: [ opts.index ] }, view: { equal: [ opts.mailbox ] } });
- if (!vs.size() && opts.mailbox != this.folder) {
- vs = this.viewport.getSelection(opts.mailbox).search({ imapuid: { equal: [ opts.index ] } });
- }
- } else {
- vs = this.viewport.createSelection('dataob', opts.index);
- }
- } else {
- vs = this.viewport.getSelected();
- }
-
- return vs;
- },
-
- _doMsgAction: function(type, opts, args)
- {
- var vs = this._getFlagSelection(opts);
-
- if (vs.size()) {
- // This needs to be synchronous Ajax if we are calling from a
- // popup window because Mozilla will not correctly call the
- // callback function if the calling window has been closed.
- DimpCore.doAction(type, this.viewport.addRequestParams(args), vs, this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)), { asynchronous: !(opts.index && opts.mailbox) });
- return vs;
- }
-
- return false;
- },
-
- // spam = (boolean) True for spam, false for innocent
- // opts = 'index', 'mailbox'
- reportSpam: function(spam, opts)
- {
- opts = opts || {};
- if (this._doMsgAction('ReportSpam', opts, { spam: spam })) {
- // Indicate to the user that something is happening (since spam
- // reporting may not be instantaneous).
- this.loadingImg('viewport', true);
- }
- },
-
- // blacklist = (boolean) True for blacklist, false for whitelist
- // opts = 'index', 'mailbox'
- blacklist: function(blacklist, opts)
- {
- opts = opts || {};
- this._doMsgAction('Blacklist', opts, { blacklist: blacklist });
- },
-
- // opts = 'index', 'mailbox'
- deleteMsg: function(opts)
- {
- opts = opts || {};
- var vs = this._getFlagSelection(opts);
-
- // Make sure that any given row is not deleted more than once. Need to
- // explicitly mark here because message may already be flagged deleted
- // when we load page (i.e. switching to using trash folder).
- vs = vs.search({ isdel: { not: [ true ] } });
- if (!vs.size()) {
- return;
- }
- vs.set({ isdel: true });
-
- opts.vs = vs;
-
- this._doMsgAction('DeleteMessage', opts, {});
- this.updateFlag(vs, '\\deleted', true);
- },
-
- // flag = (string) IMAP flag name
- // set = (boolean) True to set flag
- // opts = (Object) 'index', 'mailbox', 'noserver'
- flag: function(flag, set, opts)
- {
- opts = opts || {};
- var flags = [ (set ? '' : '-') + flag ],
- vs = this._getFlagSelection(opts);
-
- if (!vs.size()) {
- return;
- }
-
- switch (flag) {
- case '\\answered':
- if (set) {
- this.updateFlag(vs, '\\flagged', false);
- flags.push('-\\flagged');
- }
- break;
-
- case '\\deleted':
- vs.set({ isdel: false });
- break;
-
- case '\\seen':
- vs.get('dataob').each(function(s) {
- this.updateSeenUID(s, set);
- }, this);
- break;
- }
-
- this.updateFlag(vs, flag, set);
- if (!opts.noserver) {
- DimpCore.doAction('FlagMessage', { flags: flags.toJSON(), view: this.folder }, vs);
- }
- },
-
- // type = (string) 'seen' or 'unseen'
- // mbox = (string) The mailbox to flag
- flagAll: function(type, set, mbox)
- {
- DimpCore.doAction('FlagAll', { flags: [ type ].toJSON(), set: Number(set), view: mbox }, null, this.bcache.get('flagAC') || this.bcache.set('flagAC', this._flagAllCallback.bind(this)));
- },
-
- hasFlag: function(f, r)
- {
- return r.flag && this.convertFlag(f, r.flag.include(f));
- },
-
- convertFlag: function(f, set)
- {
- /* For some flags, we need to do an inverse match (e.g. knowing a
- * message is SEEN is not as important as knowing the message lacks
- * the SEEN FLAG). This function will determine if, for a given flag,
- * the inverse action should be taken on it. */
- return DIMP.conf.flags[f].n ? !set : set;
- },
-
- updateFlag: function(vs, flag, add)
- {
- add = this.convertFlag(flag, add);
-
- vs.get('dataob').each(function(ob) {
- this._updateFlag(ob, flag, add);
-
- /* If this is a search mailbox, also need to update flag in base
- * view, if it is in the buffer. */
- if (this.isSearch()) {
- var tmp = this.viewport.getSelection(ob.view).search({ imapuid: { equal: [ ob.imapuid ] }, view: { equal: [ ob.view ] } });
- if (tmp.size()) {
- this._updateFlag(tmp.get('dataob').first(), flag, add);
- }
- }
- }, this);
- },
-
- _updateFlag: function(ob, flag, add)
- {
- ob.flag = ob.flag
- ? ob.flag.without(flag)
- : [];
-
- if (add) {
- ob.flag.push(flag);
- }
-
- this.viewport.updateRow(ob);
- },
-
- /* Miscellaneous folder actions. */
- purgeDeleted: function()
- {
- DimpCore.doAction('PurgeDeleted', this.viewport.addRequestParams({}), null, this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this)));
- },
-
- modifyPoll: function(folder, add)
- {
- DimpCore.doAction('ModifyPoll', { view: folder, add: Number(add) }, null, this.bcache.get('modifyPFC') || this.bcache.set('modifyPFC', this._modifyPollCallback.bind(this)));
- },
-
- _modifyPollCallback: function(r)
- {
- r = r.response;
- var f = r.folder, fid, p = { response: { poll: {} } };
- fid = $(this.getFolderId(f));
-
- if (r.add) {
- p.response.poll[f] = r.poll.u;
- fid.writeAttribute('u', 0);
- } else {
- p.response.poll[f] = 0;
- }
-
- this._pollCallback(p);
-
- if (!r.add) {
- fid.removeAttribute('u');
- }
- },
-
- loadingImg: function(id, show)
- {
- var c;
-
- if (show) {
- $(id + 'Loading').clonePosition(id == 'viewport' ? 'msgList' : 'splitBar', { setHeight: false, setWidth: false }).show();
- c = 'progress';
- } else {
- Effect.Fade(id + 'Loading', { duration: 0.2 });
- c = 'default';
- }
- $(document.body).setStyle({ cursor: c });
- },
-
- // p = (element) Parent element
- // c = (element) Child element
- isSubfolder: function(p, c)
- {
- var sf = $(this.getSubFolderId(p.identify()));
- return sf && c.descendantOf(sf);
- },
-
- /* Pref updating function. */
- _updatePrefs: function(pref, value)
- {
- new Ajax.Request(DimpCore.addURLParam(DIMP.conf.URI_PREFS), { parameters: { app: 'imp', pref: pref, value: value } });
- },
-
- /* Onload function. */
- onDomLoad: function()
- {
- DimpCore.init();
-
- var DM = DimpCore.DMenu;
-
- /* Register global handlers now. */
- document.observe('keydown', this.keydownHandler.bindAsEventListener(this));
-
- /* Limit to folders sidebar only. */
- $('foldersSidebar').observe('mouseover', this.mouseoverHandler.bindAsEventListener(this));
-
- /* Limit to msgList only. */
- $('msgList').observe('dblclick', this.dblclickHandler.bindAsEventListener(this));
-
- $('dimpLoading').hide();
- $('dimpPage').show();
-
- /* Create the folder list. Any pending notifications will be caught
- * via the return from this call. */
- DimpCore.doAction('ListFolders', {}, null, this._folderLoadCallback.bind(this));
-
- /* Start message list loading as soon as possible. */
- if (Horde.dhtmlHistory.initialize()) {
- Horde.dhtmlHistory.addListener(this.go.bind(this));
- }
-
- /* Initialize the starting page if necessary. addListener() will have
- * already fired if there is a current location so only do a go()
- * call if there is no current location. */
- if (!Horde.dhtmlHistory.getCurrentLocation()) {
- if (DIMP.conf.login_view == 'inbox') {
- this.go('folder:INBOX');
- } else {
- this.go('portal');
- if (DIMP.conf.background_inbox) {
- this.loadMailbox('INBOX', { background: true });
- }
- }
- }
-
- this._setFilterText(true);
-
- /* Add popdown menus. Check for disabled compose at the same time. */
- this._addMouseEvents({ id: 'button_other', type: 'otheractions' }, $('button_other'));
- this._addMouseEvents({ id: 'folderopts', type: 'folderopts' }, $('folderopts').down(1));
-
- DM.addSubMenu('ctx_message_reply', 'ctx_reply');
- [ 'ctx_message_', 'oa_', 'ctx_draft_' ].each(function(i) {
- if ($(i + 'setflag')) {
- DM.addSubMenu(i + 'setflag', 'ctx_flag');
- DM.addSubMenu(i + 'unsetflag', 'ctx_flag');
- }
- });
-
- if (DIMP.conf.disable_compose) {
- $('button_reply', 'button_forward').compact().invoke('up', 'SPAN').concat($('button_compose', 'composelink', 'ctx_contacts_new')).compact().invoke('remove');
- } else {
- this._addMouseEvents({ id: 'button_reply', type: 'reply' }, $('button_reply'));
- DM.disable('button_reply_img', true, true);
- }
-
- new Drop('dropbase', this._folderDropConfig);
-
- if (DIMP.conf.toggle_pref) {
- this._toggleHeaders($('th_expand'));
- }
-
- this._resizeIE6();
-
- /* Remove unavailable menu items. */
- if (!$('GrowlerLog')) {
- $('alertsloglink').remove();
- }
-
- /* Check for new mail. */
- this.setPoll();
-
- /* Init quicksearch. */
- if ($('qsearch')) {
- $('qsearch_input').observe('blur', this._quicksearchOnBlur.bind(this));
- this._addMouseEvents({ id: 'qsearch_icon', left: true, offset: 'qsearch', type: 'qsearchopts' });
- }
-
- if (DimpCore.is_ie6) {
- /* Disable text selection in preview pane for IE 6. */
- document.observe('selectstart', Event.stop);
- Event.observe(window, 'resize', this._resizeIE6.bind(this));
-
- /* Since IE 6 doesn't support hover over non-links, use javascript
- * events to replicate mouseover CSS behavior. */
- $('dimpbarActions', 'serviceActions', 'applicationfolders', 'specialfolders', 'normalfolders').compact().invoke('select', 'LI').flatten().compact().each(function(e) {
- e.observe('mouseover', e.addClassName.curry('over')).observe('mouseout', e.removeClassName.curry('over'));
- });
-
- /* These are links, but they have no href attribute. Hovering
- * requires something in href on IE6. */
- $$('.context A').each(function(e) {
- e.writeAttribute('href', '');
- });
- }
- },
-
- // IE 6 width fixes (See Bug #6793)
- _resizeIE6: function()
- {
- if (DimpCore.is_ie6) {
- var tmp = parseInt($('sidebarPanel').getStyle('width'), 10),
- tmp1 = document.viewport.getWidth() - tmp - 30;
- $('normalfolders').setStyle({ width: tmp + 'px' });
- $('dimpmain').setStyle({ width: tmp1 + 'px' });
- $('msglist').setStyle({ width: (tmp1 - 5) + 'px' });
- $('msgBody').setStyle({ width: (tmp1 - 25) + 'px' });
- tmp = $('dimpmain_portal').down('IFRAME');
- if (tmp) {
- this._resizeIE6Iframe(tmp);
- }
- }
- },
-
- _resizeIE6Iframe: function(iframe)
- {
- if (DimpCore.is_ie6) {
- iframe.setStyle({ width: $('dimpmain').getStyle('width'), height: (document.viewport.getHeight() - 20) + 'px' });
- }
- }
-
-};
-
-/* Need to add after DimpBase is defined. */
-DimpBase._msgDragConfig = {
- scroll: 'normalfolders',
- threshold: 5,
- caption: DimpBase.dragCaption.bind(DimpBase),
- onStart: function(d, e) {
- var args = { right: e.isRightClick() },
- id = d.element.id;
-
- d.selectIfNoDrag = false;
-
- // Handle selection first.
- if (!args.right && (e.ctrlKey || e.metaKey)) {
- DimpBase.msgSelect(id, $H({ ctrl: true }).merge(args).toObject());
- } else if (e.shiftKey) {
- DimpBase.msgSelect(id, $H({ shift: true }).merge(args).toObject());
- } else if (e.element().hasClassName('msCheck')) {
- DimpBase.msgSelect(id, { ctrl: true, right: true });
- } else if (DimpBase.isSelected('domid', id)) {
- if (!args.right && DimpBase.selectedCount()) {
- d.selectIfNoDrag = true;
- }
- } else {
- DimpBase.msgSelect(id, args);
- }
- },
- onEnd: function(d, e) {
- if (d.selectIfNoDrag && !d.wasDragged) {
- DimpBase.msgSelect(d.element.id, { right: e.isRightClick() });
- }
- }
-};
-
-DimpBase._folderDragConfig = {
- ghosting: true,
- offset: { x: 15, y: 0 },
- scroll: 'normalfolders',
- threshold: 5,
- onDrag: function(d, e) {
- if (!d.wasDragged) {
- $('folderopts').hide();
- $('dropbase').show();
- d.ghost.removeClassName('on');
- }
- },
- onEnd: function(d, e) {
- if (d.wasDragged) {
- $('folderopts').show();
- $('dropbase').hide();
- }
- }
-};
-
-DimpBase._folderDropConfig = {
- caption: function(drop, drag, e) {
- var m,
- d = drag.readAttribute('l'),
- ftype = drop.readAttribute('ftype'),
- l = drop.readAttribute('l');
-
- if (drop == $('dropbase')) {
- return DIMP.text.moveto.replace(/%s/, d).replace(/%s/, DIMP.text.baselevel);
- } else {
- switch (e.type) {
- case 'mousemove':
- m = (e.ctrlKey) ? DIMP.text.copyto : DIMP.text.moveto;
- break;
-
- case 'keydown':
- /* Can't use ctrlKey here since different browsers handle
- * the ctrlKey in different ways when it comes to firing
- * keybaord events. */
- m = (e.keyCode == 17) ? DIMP.text.copyto : DIMP.text.moveto;
- break;
-
- case 'keyup':
- if (e.keyCode == 17) {
- m = DIMP.text.moveto;
- } else {
- m = (e.ctrlKey) ? DIMP.text.copyto : DIMP.text.moveto;
- }
- break;
- }
- if (drag.hasClassName('folder')) {
- return (ftype != 'special' && !DimpBase.isSubfolder(drag, drop)) ? m.replace(/%s/, d).replace(/%s/, l) : '';
- } else {
- return ftype != 'container' ? m.replace(/%s/, DimpBase.dragCaption()).replace(/%s/, l) : '';
- }
- }
- },
- keypress: true,
- onDrop: DimpBase._folderDropHandler.bind(DimpBase)
-};
-
-/* Need to register a callback function for doAction to catch viewport
- * information returned from the server. */
-DimpCore.onDoActionComplete = function(r) {
- if (DimpBase.viewport) {
- DimpBase.viewport.parseJSONResponse(r);
- }
-};
-
-/* Click handler. */
-DimpCore.clickHandler = DimpCore.clickHandler.wrap(DimpBase.clickHandler.bind(DimpBase));
-
-/* ContextSensitive functions. */
-DimpCore.contextOnClick = DimpCore.contextOnClick.wrap(DimpBase.contextOnClick.bind(DimpBase));
-DimpCore.contextOnShow = DimpCore.contextOnShow.wrap(DimpBase.contextOnShow.bind(DimpBase));
-
-/* Initialize onload handler. */
-document.observe('dom:loaded', DimpBase.onDomLoad.bind(DimpBase));
+++ /dev/null
-/**
- * DimpCore.js - Dimp UI application logic.
- *
- * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-/* DimpCore object. */
-var DimpCore = {
- // Vars used and defaulting to null/false:
- // DMenu, Growler, inAjaxCallback, is_init, is_logout,
- // onDoActionComplete
- growler_log: true,
- is_ie6: false /*@cc_on || @_jscript_version < 5.7 @*/,
- server_error: 0,
-
- doActionOpts: {
- onException: function(r, e) { DimpCore.debug('onException', e); },
- onFailure: function(t, o) { DimpCore.debug('onFailure', t); },
- evalJS: false,
- evalJSON: true
- },
-
- debug: function(label, e)
- {
- if (!this.is_logout && DIMP.conf.debug) {
- if (console && console.error) {
- // Firebug error reporting.
- console.error(label, e);
- } else {
- alert(label + ': ' + ((e instanceof Error && e.name && e.message) ? e.name + '-' + e.message : Object.inspect(e)) + (e.lineNumber ? ' (Line #' + e.lineNumber + ')' : ''));
- }
- }
- },
-
- // Convert object to an IMP UID Range string. See IMP::toRangeString()
- // ob = (object) mailbox name as keys, values are array of uids.
- toRangeString: function(ob)
- {
- var str = '';
-
- $H(ob).each(function(o) {
- if (!o.value.size()) {
- return;
- }
-
- var u = o.value.numericSort(),
- first = u.shift(),
- last = first,
- out = [];
-
- u.each(function(k) {
- if (last + 1 == k) {
- last = k;
- } else {
- out.push(first + (last == first ? '' : (':' + last)));
- first = last = k;
- }
- });
- out.push(first + (last == first ? '' : (':' + last)));
- str += '{' + o.key.length + '}' + o.key + out.join(',');
- });
-
- return str;
- },
-
- // Parses an IMP UID Range string. See IMP::parseRangeString()
- // str = (string) An IMP UID range string.
- parseRangeString: function(str)
- {
- var count, end, i, mbox,
- mlist = {},
- uids = [];
- str = str.strip();
-
- while (!str.blank()) {
- if (!str.startsWith('{')) {
- break;
- }
- i = str.indexOf('}');
- count = Number(str.substr(1, i - 1));
- mbox = str.substr(i + 1, count);
- i += count + 1;
- end = str.indexOf('{', i);
- if (end == -1) {
- uidstr = str.substr(i);
- str = '';
- } else {
- uidstr = str.substr(i, end - i);
- str = str.substr(end);
- }
-
- uidstr.split(',').each(function(e) {
- var r = e.split(':');
- if (r.size() == 1) {
- uids.push(Number(e));
- } else {
- uids = uids.concat($A($R(Number(r[0]), Number(r[1]))));
- }
- });
-
- mlist[mbox] = uids;
- }
-
- return mlist;
- },
-
- /* 'action' -> if action begins with a '*', the exact string will be used
- * instead of sending the action to the IMP handler. */
- doAction: function(action, params, uids, callback, opts)
- {
- var b, tmp = {};
-
- opts = Object.extend(this.doActionOpts, opts || {});
- params = $H(params);
- action = action.startsWith('*')
- ? action.substring(1)
- : DIMP.conf.URI_AJAX + '/' + action;
-
- if (uids) {
- if (uids.viewport_selection) {
- b = uids.getBuffer();
- if (b.getMetaData('search')) {
- uids.get('dataob').each(function(r) {
- if (!tmp[r.view]) {
- tmp[r.view] = [];
- }
- tmp[r.view].push(r.imapuid);
- });
- } else {
- tmp[b.getView()] = uids.get('uid');
- }
- uids = tmp;
- }
- params.set('uid', this.toRangeString(uids));
- }
-
- opts.parameters = this.addRequestParams(params);
- opts.onComplete = function(t, o) { this.doActionComplete(t, callback); }.bind(this);
- new Ajax.Request(action, opts);
- },
-
- // params - (Hash)
- addRequestParams: function(params)
- {
- var p = params.clone();
-
- if (DIMP.conf.SESSION_ID) {
- p.update(DIMP.conf.SESSION_ID.toQueryParams());
- }
-
- return p;
- },
-
- doActionComplete: function(request, callback)
- {
- this.inAjaxCallback = true;
-
- if (!request.responseJSON) {
- if (++this.server_error == 3) {
- this.showNotifications([ { type: 'horde.error', message: DIMP.text.ajax_timeout } ]);
- }
- this.inAjaxCallback = false;
- return;
- }
-
- var r = request.responseJSON;
-
- if (!r.msgs) {
- r.msgs = [];
- }
-
- if (r.response && Object.isFunction(callback)) {
- try {
- callback(r);
- } catch (e) {
- this.debug('doActionComplete', e);
- }
- }
-
- if (this.server_error >= 3) {
- r.msgs.push({ type: 'horde.success', message: DIMP.text.ajax_recover });
- }
- this.server_error = 0;
-
- this.showNotifications(r.msgs);
-
- if (r.response && this.onDoActionComplete) {
- this.onDoActionComplete(r.response);
- }
-
- this.inAjaxCallback = false;
- },
-
- setTitle: function(title)
- {
- document.title = DIMP.conf.name + ' :: ' + title;
- },
-
- showNotifications: function(msgs)
- {
- if (!msgs.size() || this.is_logout) {
- return;
- }
-
- msgs.find(function(m) {
- var log = 0;
-
- switch (m.type) {
- case 'dimp.timeout':
- this.logout(DIMP.conf.URI_TIMEOUT);
- return true;
-
- case 'horde.error':
- case 'horde.message':
- case 'horde.success':
- case 'horde.warning':
- log = 1;
- // Fall through to below case.
-
- case 'imp.reply':
- case 'imp.forward':
- case 'imp.redirect':
- this.Growler.growl(m.message, {
- className: m.type.replace('.', '-'),
- life: 8,
- log: log,
- sticky: m.type == 'horde.error'
- });
- }
- }, this);
- },
-
- compose: function(type, args)
- {
- var url = DIMP.conf.URI_COMPOSE;
- args = args || {};
- if (type) {
- args.type = type;
- }
- this.popupWindow(this.addURLParam(url, args), 'compose' + new Date().getTime());
- },
-
- popupWindow: function(url, name)
- {
- if (!(window.open(url, name.replace(/\W/g, '_'), 'width=' + DIMP.conf.popup_width + ',height=' + DIMP.conf.popup_height + ',status=1,scrollbars=yes,resizable=yes'))) {
- this.showNotifications([ { type: 'horde.warning', message: DIMP.text.popup_block } ]);
- }
- },
-
- closePopup: function()
- {
- // Mozilla bug/feature: it will not close a browser window
- // automatically if there is code remaining to be performed (or, at
- // least, not here) unless the mouse is moved or a keyboard event
- // is triggered after the callback is complete. (As of FF 2.0.0.3 and
- // 1.5.0.11). So wait for the callback to complete before attempting
- // to close the window.
- if (this.inAjaxCallback) {
- this.closePopup.bind(this).defer();
- } else {
- window.close();
- }
- },
-
- logout: function(url)
- {
- this.is_logout = true;
- this.redirect(url || (DIMP.conf.URI_AJAX + '/LogOut'));
- },
-
- redirect: function(url, force)
- {
- var ptr = parent.frames.horde_main ? parent : window;
- ptr.location = this.addURLParam(url);
- if (force) {
- setTimeout(function() { ptr.location.reload() }, 300);
- }
- },
-
- /* Add dropdown menus to addresses. */
- buildAddressLinks: function(alist, elt)
- {
- var base, tmp,
- cnt = alist.size();
-
- if (cnt > 15) {
- tmp = $('largeaddrspan').cloneNode(true).writeAttribute('id', 'largeaddrspan_active');
- elt.insert(tmp);
- base = tmp.down('.dispaddrlist');
- tmp = tmp.down(1);
- tmp.setText(tmp.getText().replace('%d', cnt));
- } else {
- base = elt;
- }
-
- alist.each(function(o, i) {
- var a;
- if (o.raw) {
- a = o.raw;
- } else {
- a = new Element('A', { className: 'address', personal: o.personal, email: o.inner, address: (o.personal ? (o.personal + ' <' + o.inner + '>') : o.inner) });
- if (o.personal) {
- a.writeAttribute({ title: o.inner }).insert(o.personal.escapeHTML());
- } else {
- a.insert(o.inner.escapeHTML());
- }
- this.DMenu.addElement(a.identify(), 'ctx_contacts', { offset: a, left: true });
- }
- base.insert(a);
- if (i + 1 != cnt) {
- base.insert(', ');
- }
- }, this);
-
- return elt;
- },
-
- /* Add message log info to message view. */
- updateMsgLog: function(log)
- {
- var tmp = '';
- log.each(function(entry) {
- tmp += '<li><span class="iconImg imp-' + entry.t + '"></span>' + entry.m + '</li>';
- });
- $('msgloglist').down('UL').update(tmp);
- },
-
- /* Removes event handlers from address links. */
- removeAddressLinks: function(id)
- {
- id.select('.address').each(function(elt) {
- this.DMenu.removeElement(elt.identify());
- }, this);
- },
-
- addURLParam: function(url, params)
- {
- var q = url.indexOf('?');
- params = $H(params);
-
- if (DIMP.conf.SESSION_ID) {
- params.update(DIMP.conf.SESSION_ID.toQueryParams());
- }
-
- if (q != -1) {
- params.update(url.toQueryParams());
- url = url.substring(0, q);
- }
-
- return params.size() ? (url + '?' + params.toQueryString()) : url;
- },
-
- reloadMessage: function(params)
- {
- if (typeof DimpFullmessage != 'undefined') {
- window.location = this.addURLParam(document.location.href, params);
- } else {
- DimpBase.loadPreview(null, params);
- }
- },
-
- /* Mouse click handler. */
- clickHandler: function(e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = e.element(), id, tmp;
-
- while (Object.isElement(elt)) {
- id = elt.readAttribute('id');
-
- switch (id) {
- case 'msg_print':
- window.print();
- break;
-
- case 'alertsloglink':
- $('alertsloglink').down('A').update(this.Growler.toggleLog() ? DIMP.text.hidealog : DIMP.text.showalog);
- break;
-
- case 'largeaddrspan_active':
- tmp = elt.down();
- [ tmp.down(), tmp.down(1), tmp.next() ].invoke('toggle');
- break;
-
- default:
- // CSS class based matching
- if (elt.hasClassName('unblockImageLink')) {
- IMP.unblockImages(e);
- } else if (elt.hasClassName('toggleQuoteShow')) {
- [ elt, elt.next() ].invoke('toggle');
- Effect.BlindDown(elt.next(1), { duration: 0.2, queue: { position: 'end', scope: 'showquote', limit: 2 } });
- } else if (elt.hasClassName('toggleQuoteHide')) {
- [ elt, elt.previous() ].invoke('toggle');
- Effect.BlindUp(elt.next(), { duration: 0.2, queue: { position: 'end', scope: 'showquote', limit: 2 } });
- } else if (elt.hasClassName('pgpVerifyMsg')) {
- elt.replace(DIMP.text.verify);
- DimpCore.reloadMessage({ pgp_verify_msg: 1 });
- e.stop();
- } else if (elt.hasClassName('smimeVerifyMsg')) {
- elt.replace(DIMP.text.verify);
- DimpCore.reloadMessage({ smime_verify_msg: 1 });
- e.stop();
- }
- break;
- }
-
- elt = elt.up();
- }
- },
-
- // By default, no context onShow action
- contextOnShow: Prototype.emptyFunction,
-
- contextOnClick: function(elt, baseelt, menu)
- {
- switch (elt.readAttribute('id')) {
- case 'ctx_contacts_new':
- this.compose('new', { to: baseelt.readAttribute('address') });
- break;
-
- case 'ctx_contacts_add':
- this.doAction('AddContact', { name: baseelt.readAttribute('personal'), email: baseelt.readAttribute('email') }, null, true);
- break;
- }
- },
-
- /* DIMP initialization function. */
- init: function()
- {
- if (this.is_init) {
- return;
- }
- this.is_init = true;
-
- if (typeof ContextSensitive != 'undefined') {
- this.DMenu = new ContextSensitive({
- onClick: this.contextOnClick.bind(this),
- onShow: this.contextOnShow.bind(this)
- });
- }
-
- /* Don't do additional onload stuff if we are in a popup. We need a
- * try/catch block here since, if the page was loaded by an opener
- * out of this current domain, this will throw an exception. */
- try {
- if (parent.opener &&
- parent.opener.location.host == window.location.host &&
- parent.opener.DimpCore) {
- DIMP.baseWindow = parent.opener.DIMP.baseWindow || parent.opener;
- }
- } catch (e) {}
-
- /* Add Growler notification handler. */
- this.Growler = new Growler({
- location: 'br',
- log: this.growler_log,
- noalerts: DIMP.text.noalerts
- });
-
- /* Add click handler. */
- document.observe('click', DimpCore.clickHandler.bindAsEventListener(DimpCore));
- }
-
-};
+++ /dev/null
-/**
- * DimpSlider.js - A minimalist library to create a slider that acts like a
- * browser's native scrollbar.
- * Requires prototype.js 1.6.0.2+
- *
- * Adapted from script.aculo.us slider.js v1.8.0
- * (c) 2005-2007 Marty Haught, Thomas Fuchs
- * http://script.aculo.us/
- *
- * The original script was freely distributable under the terms of an
- * MIT-style license.
- *
- * 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 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.
- *
- * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
- *
- * @author Michael Slusarz <slusarz@curecanti.org>
- */
-
-var DimpSlider = Class.create({
- value: 0,
-
- initialize: function(track, options)
- {
- this.track = $(track);
- this.options = Object.extend({
- buttonclass: null,
- cursorclass: null,
- pagesize: 0,
- totalsize: 0
- }, options || {});
-
- this.handle = new Element('DIV', { className: this.options.cursorclass }).makePositioned();
- this.track.insert(this.handle);
-
- if (this.options.buttonclass) {
- this.sbup = new Element('DIV', { className: this.options.buttonclass.up });
- this.sbdown = new Element('DIV', { className: this.options.buttonclass.down }).makePositioned();
- this.handle.insert({ before: this.sbup, after: this.sbdown });
- [ this.sbup, this.sbdown ].invoke('observe', 'mousedown', this._arrowClick.bindAsEventListener(this));
- }
-
- this.sbdownsize = this.sbupsize = this.value = 0;
- this.active = this.dragging = false;
-
- if (this._showScroll()) {
- this._initScroll();
- }
-
- this.eventMU = this._endDrag.bindAsEventListener(this);
- this.eventMM = this._update.bindAsEventListener(this);
-
- [ this.handle, this.track ].invoke('observe', 'mousedown', this._startDrag.bindAsEventListener(this));
- },
-
- _initScroll: function()
- {
- if (this.init) {
- return false;
- }
- this.init = true;
- this.track.show();
- if (this.sbup) {
- this.sbupsize = this.sbup.offsetHeight;
- this.sbdownsize = this.sbdown.offsetHeight;
- }
- this._updateHandleLength();
- return true;
- },
-
- _startDrag: function(e)
- {
- if (!e.isLeftClick()) {
- return;
- }
-
- var dir,
- hoffsets = this.handle.cumulativeOffset();
-
- if (e.element() == this.track) {
- dir = (e.pointerY() < hoffsets[1]) ? -1 : 1;
- this.setScrollPosition(this.getValue() - dir + (this.options.pagesize * dir));
- } else {
- this.curroffsets = this.track.cumulativeOffset();
- this.offsetY = e.pointerY() - hoffsets[1] + this.sbupsize;
- this.active = true;
-
- document.observe('mouseup', this.eventMU);
- document.observe('mousemove', this.eventMM);
- }
-
- e.stop();
- },
-
- _update: function(e)
- {
- if (this.active) {
- this.dragging = true;
- this._setScrollPosition('px', Math.min(Math.max(0, e.pointerY() - this.offsetY - this.curroffsets[1]), this.handletop));
- if (this.options.onSlide) {
- this.options.onSlide();
- }
- if (Prototype.Browser.WebKit) {
- window.scrollBy(0,0);
- }
- e.stop();
- }
- },
-
- _endDrag: function(e)
- {
- if (this.active && this.dragging) {
- this._updateFinished();
- e.stop();
-
- document.stopObserving('mouseup', this.eventMU);
- document.stopObserving('mousemove', this.eventMM);
- }
- this.active = this.dragging = false;
- },
-
- _arrowClick: function(e)
- {
- this.setScrollPosition(this.getValue() + ((e.element() == this.sbup) ? -1 : 1));
- },
-
- _updateFinished: function()
- {
- if (this.options.onChange) {
- this.options.onChange();
- }
- },
-
- updateHandleLength: function(pagesize, totalsize)
- {
- this.options.pagesize = pagesize;
- this.options.totalsize = totalsize;
- if (!this._showScroll()) {
- this.value = 0;
- this.track.hide();
- return;
- }
- if (!this._initScroll()) {
- this.track.show();
- this._updateHandleLength();
- }
- },
-
- _updateHandleLength: function()
- {
- var t = this.track.offsetHeight - this.sbupsize - this.sbdownsize;
-
- // Minimum handle size = 10px
- this.handle.setStyle({ height: Math.max(10, Math.round((this.options.pagesize / this.options.totalsize) * t)) + 'px' });
- this.handletop = t - this.handle.offsetHeight;
- if (this.sbdown) {
- this.sbdown.setStyle({ top: this.handletop + 'px' });
- }
- this._setScrollPosition('val', this.getValue());
- },
-
- getValue: function()
- {
- return this.value;
- },
-
- setScrollPosition: function(val)
- {
- if (this._showScroll()) {
- var oldval = this.getValue();
- this._setScrollPosition('val', val);
- if (oldval != this.getValue()) {
- this._updateFinished();
- }
- }
- },
-
- _setScrollPosition: function(type, data)
- {
- this.value = (type == 'val')
- ? Math.min(Math.max(0, data), this.options.totalsize - this.options.pagesize)
- : Math.max(0, Math.round(Math.min(data, this.handletop) / this.handletop * (this.options.totalsize - this.options.pagesize)));
- this.handlevalue = (type == 'px')
- ? data
- : Math.round(this.getValue() / (this.options.totalsize - this.options.pagesize) * this.handletop);
- this.handle.setStyle({ top: this.handlevalue + 'px' });
- },
-
- _showScroll: function()
- {
- return (this.options.pagesize < this.options.totalsize);
- }
-});
+++ /dev/null
-/**
- * ViewPort.js - Code to create a viewport window in a web browser.
- *
- * Usage:
- * ======
- * var viewport = new ViewPort({ options });
- *
- * Required options:
- * -----------------
- * ajax_url: (string) TODO
- * Response: 'ViewPort'
- * content: (Element/string) A DOM element/ID of the container to hold the
- * viewport rows.
- * template: (string) TODO DIV with 'vpData'
- * Class: 'vpRow' 'vpRowSelected'
- *
- * Optional options:
- * -----------------
- * ajax_opts: (object) TODO
- * buffer_pages: (integer) The number of viewable pages to send to the browser
- * per server access when listing rows.
- * empty_msg: (string) A string to display when the view is empty. Inserted in
- * a SPAN element with class 'vpEmpty'.
- * limit_factor: (integer) When browsing through a list, if a user comes
- * within this percentage of the end of the current cached
- * viewport, send a background request to the server to retrieve
- * the next slice.
- * page_size: (integer) Default page size to view on load.
- * show_split_pane: (boolean) Show the split pane on load?
- * split_bar: (Element/string) A DOM element/ID of the element used to display
- * the split bar.
- * split_pane: (Element/string) A DOM element/ID of the container to hold
- * the split pane info.
- * wait: (integer) How long, in seconds, to wait before displaying an
- * informational message to users that the message list is still being
- * built.
- *
- * Callbacks:
- * ----------
- * onAjaxRequest
- * onAjaxResponse
- * onCachedList
- * onCacheUpdate
- * onClear
- * onContent
- * onContentComplete
- * onDeselect
- * onEndFetch
- * onFetch
- * onSelect
- * onSlide
- * onSplitBarChange
- * onWait
- *
- * Outgoing AJAX request has the following params (TODO):
- * ------------------------------------------------------
- * For a row request:
- * request_id: (integer) TODO
- * slice: (string)
- *
- * For a search request:
- * request_id: (integer) TODO
- * search: (JSON object)
- * search_after: (integer)
- * search_before: (integer)
- *
- * For a rangeslice request:
- * rangeslice: (boolean)
- * slice: (string)
- *
- * Incoming AJAX response has the following params (TODO):
- * -------------------------------------------------------
- * cacheid
- * data
- * label
- * metadata (optional)
- * request_id
- * rangelist: TODO
- * reset (optional) - If set, purges all cached data
- * resetmd (optional) - If set, purges all user metadata
- * rowlist
- * rownum (optional)
- * totalrows
- * update (optional) - If set, update the rowlist instead of overwriting it.
- * view
- *
- * Requires prototypejs 1.6+, DimpSlider.js, scriptaculous 1.8+ (effects.js
- * only), and Horde's dragdrop2.js.
- *
- * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-/**
- * ViewPort
- */
-var ViewPort = Class.create({
-
- initialize: function(opts)
- {
- this.opts = Object.extend({
- buffer_pages: 5,
- limit_factor: 35
- }, opts);
-
- this.opts.content = $(opts.content);
- this.opts.split_pane = $(opts.split_pane);
-
- this.scroller = new ViewPort_Scroller(this);
- this.template = new Template(opts.template);
-
- this.views = {};
-
- this.split_bar_loc = opts.page_size;
- this.show_split_pane = opts.show_split_pane;
-
- this.isbusy = this.line_height = this.page_size = this.split_bar = null;
- this.request_num = 1;
-
- // Init empty string now.
- this.empty_msg = new Element('SPAN', { className: 'vpEmpty' }).insert(opts.empty_msg);
-
- // Set up AJAX response function.
- this.ajax_response = this.opts.onAjaxResponse || this._ajaxRequestComplete.bind(this);
-
- Event.observe(window, 'resize', this.onResize.bind(this));
- },
-
- // view = ID of view.
- // search = (object) Search parameters
- // background = Load view in background?
- loadView: function(view, search, background)
- {
- var buffer, curr, init = true, opts = {}, ps;
-
- this._clearWait();
-
- // Need a page size before we can continue - this is what determines
- // the slice size to request from the server.
- if (this.page_size === null) {
- ps = this.getPageSize(this.show_split_pane ? 'default' : 'max');
- if (isNaN(ps)) {
- return this.loadView.bind(this, view, search, background).defer();
- }
- this.page_size = ps;
- }
-
- if (this.view) {
- if (!background) {
- // Need to store current buffer to save current offset
- buffer = this._getBuffer();
- buffer.setMetaData({ offset: this.currentOffset() }, true);
- this.views[this.view] = buffer;
- }
- init = false;
- }
-
- if (background) {
- opts = { background: true, view: view };
- } else {
- if (!this.view) {
- this.onResize(true);
- } else if (this.view != view) {
- this.active_req = null;
- }
- this.view = view;
- }
-
- if (curr = this.views[view]) {
- this._updateContent(curr.getMetaData('offset') || 0, opts);
- if (!background) {
- this._ajaxRequest({ checkcache: 1 });
- }
- return;
- }
-
- if (!init) {
- if (this.opts.onClear) {
- this.opts.onClear(this.visibleRows());
- }
- this.opts.content.update();
- this.scroller.clear();
- }
-
- this.views[view] = buffer = this._getBuffer(view, true);
-
- if (search) {
- opts.search = search;
- } else {
- opts.offset = 0;
- }
-
- opts.initial = 1;
-
- this._fetchBuffer(opts);
- },
-
- // view = ID of view
- deleteView: function(view)
- {
- delete this.views[view];
- },
-
- // rownum = (integer) Row number
- // opts = (Object) [noupdate, top] TODO
- scrollTo: function(rownum, opts)
- {
- var s = this.scroller;
- opts = opts || {};
-
- s.noupdate = opts.noupdate;
-
- switch (this.isVisible(rownum)) {
- case -1:
- s.moveScroll(rownum - 1);
- break;
-
- case 0:
- if (opts.top) {
- s.moveScroll(rownum - 1);
- }
- break;
-
- case 1:
- s.moveScroll(Math.min(rownum, this.getMetaData('total_rows') - this.getPageSize() + 1));
- break;
- }
-
- s.noupdate = false;
- },
-
- // rownum = Row number
- isVisible: function(rownum)
- {
- var offset = this.currentOffset();
- return (rownum < offset + 1)
- ? -1
- : ((rownum > (offset + this.getPageSize('current'))) ? 1 : 0);
- },
-
- // params = TODO
- reload: function(params)
- {
- this._fetchBuffer({
- offset: this.currentOffset(),
- params: $H(params).merge({ purge: true })
- });
- },
-
- // vs = (Viewport_Selection) A Viewport_Selection object.
- // opts = (object) TODO [cacheid, noupdate, view]
- remove: function(vs, opts)
- {
- if (!vs.size()) {
- return;
- }
-
- if (this.isbusy) {
- this.remove.bind(this, vs, opts).defer();
- return;
- }
-
- this.isbusy = true;
- opts = opts || {};
-
- var args,
- i = 0,
- visible = vs.get('div'),
- vsize = visible.size();
-
- this.deselect(vs);
-
- if (opts.cacheid) {
- this._getBuffer(opts.view).setMetaData({ cacheid: opts.cacheid }, true);
- }
-
- // If we have visible elements to remove, only call refresh after
- // the last effect has finished.
- if (vsize) {
- // Set 'to' to a value slightly above 0 to prevent Effect.Fade
- // from auto hiding. Hiding is unnecessary, since we will be
- // removing from the document shortly.
- args = { duration: 0.25, to: 0.01 };
- visible.each(function(v) {
- if (++i == vsize) {
- args.afterFinish = this._removeids.bind(this, vs, opts);
- }
- Effect.Fade(v, args);
- }, this);
- } else {
- this._removeids(vs, opts);
- }
- },
-
- // vs = (Viewport_Selection) A Viewport_Selection object.
- // opts = (object) TODO [noupdate, view]
- _removeids: function(vs, opts)
- {
- this._getBuffer(opts.view).setMetaData({ total_rows: this.getMetaData('total_rows', opts.view) - vs.size() }, true);
-
- if (this.opts.onClear) {
- this.opts.onClear(vs.get('div').compact());
- }
-
- this._getBuffer().remove(vs.get('rownum'));
-
- if (this.opts.onCacheUpdate) {
- this.opts.onCacheUpdate(opts.view || this.view);
- }
-
- if (!opts.noupdate) {
- this.requestContentRefresh(this.currentOffset());
- }
-
- this.isbusy = false;
- },
-
- // nowait = (boolean) TODO
- onResize: function(nowait)
- {
- if (!this.opts.content.visible()) {
- return;
- }
-
- if (this.resizefunc) {
- clearTimeout(this.resizefunc);
- }
-
- if (nowait) {
- this._onResize();
- } else {
- this.resizefunc = this._onResize.bind(this).delay(0.1);
- }
- },
-
- _onResize: function()
- {
- // This is needed for IE 6 - or else horizontal scrolling can occur.
- if (!this.opts.content.offsetHeight) {
- return this._onResize.bind(this).defer();
- }
-
- var diff, h, setpane,
- c = $(this.opts.content),
- de = document.documentElement,
- lh = this._getLineHeight();
-
- // Get split pane dimensions
- if (this.opts.split_pane) {
- if (this.show_split_pane) {
- if (!this.opts.split_pane.visible()) {
- this._initSplitBar();
- if (this.split_bar_loc &&
- this.split_bar_loc > 0) {
- this.split_bar_loc = this.page_size = Math.min(this.split_bar_loc, this.getPageSize('splitmax'));
- } else {
- this.page_size = this.getPageSize('default');
- }
- }
- setpane = true;
- } else if (this.opts.split_pane.visible()) {
- this.split_bar_loc = this.page_size;
- [ this.opts.split_pane, this.split_bar ].invoke('hide');
- }
- }
-
- if (!setpane) {
- this.page_size = this.getPageSize('max');
- }
-
- // Do some magic to ensure we never cause a horizontal scroll.
- h = lh * this.page_size;
- c.setStyle({ height: h + 'px' });
- if (setpane) {
- this.opts.split_pane.setStyle({ height: (this._getMaxHeight() - h - lh) + 'px' }).show();
- this.split_bar.show();
- } else if (diff = de.scrollHeight - de.clientHeight) {
- c.setStyle({ height: (lh * (this.page_size - 1)) + 'px' });
- }
-
- this.scroller.onResize();
- },
-
- // offset = (integer) TODO
- requestContentRefresh: function(offset)
- {
- if (!this._updateContent(offset)) {
- return false;
- }
-
- var limit = this._getBuffer().isNearingLimit(offset);
- if (limit) {
- this._fetchBuffer({
- background: true,
- nearing: limit,
- offset: offset
- });
- }
-
- return true;
- },
-
- // opts = (object) The following parameters:
- // One of the following is REQUIRED:
- // offset: (integer) Value of offset
- // search: (object) List of search keys/values
- //
- // OPTIONAL:
- // background: (boolean) Do fetch in background
- // initial: (boolean) Is this the initial access to this view?
- // nearing: (string) TODO [only used w/offset]
- // params: (object) Parameters to add to outgoing URL
- // view: (string) The view to retrieve. Defaults to current view.
- _fetchBuffer: function(opts)
- {
- if (this.isbusy) {
- return this._fetchBuffer.bind(this, opts).defer();
- }
-
- this.isbusy = true;
-
- // Only call onFetch() if we are loading in foreground.
- if (!opts.background && this.opts.onFetch) {
- this.opts.onFetch();
- }
-
- var llist, lrows, rlist, tmp, type, value,
- view = (opts.view || this.view),
- b = this._getBuffer(view),
- params = $H(opts.params),
- r_id = this.request_num++;
-
- params.update({ request_id: r_id });
-
- // Determine if we are querying via offset or a search query
- if (opts.search || opts.initial) {
- /* If this is an initial request, 'type' will be set correctly
- * further down in the code. */
- if (opts.search) {
- type = 'search';
- value = opts.search;
- params.set('search', Object.toJSON(value));
- } else {
- params.set('initial', 1);
- }
- tmp = this._lookbehind();
-
- params.update({
- search_after: this.bufferSize() - tmp,
- search_before: tmp
- });
- }
-
- if (!opts.search) {
- type = 'rownum';
- value = opts.offset + 1;
-
- // llist: keys - request_ids; vals - loading rownums
- llist = b.getMetaData('llist') || $H();
- lrows = llist.values().flatten();
-
- b.setMetaData({ req_offset: opts.offset }, true);
-
- /* If the current offset is part of a pending request, update
- * the offset. */
- if (lrows.size() &&
- !params.get('purge') &&
- b.sliceLoaded(value, lrows)) {
- /* One more hurdle. If we are loading in background, and now
- * we are in foreground, we need to search for the request
- * that contains the current rownum. For now, just use the
- * last request. */
- if (!this.active_req && !opts.background) {
- this.active_req = llist.keys().numericSort().last();
- }
- this.isbusy = false;
- return;
- }
-
- /* This gets the list of rows needed which do not already appear
- * in the buffer. */
- tmp = this._getSliceBounds(value, opts.nearing, view);
- rlist = $A($R(tmp.start, tmp.end)).diff(b.getAllRows());
-
- if (!params.get('purge') && !rlist.size()) {
- this.isbusy = false;
- return;
- }
-
- /* Add rows to the loading list for the view. */
- rlist = rlist.diff(lrows).numericSort();
- llist.set(r_id, rlist);
- b.setMetaData({ llist: llist }, true);
-
- params.update({ slice: rlist.first() + ':' + rlist.last() });
- }
-
- if (!opts.background) {
- this.active_req = r_id;
- this._handleWait();
- }
-
- this._ajaxRequest(params, { noslice: true, view: view });
-
- this.isbusy = false;
- },
-
- // rownum = (integer) Row number
- // nearing = (string) 'bottom', 'top', null
- _getSliceBounds: function(rownum, nearing)
- {
- var b_size = this.bufferSize(),
- ob = {};
-
- switch (nearing) {
- case 'bottom':
- ob.start = rownum + this.getPageSize();
- ob.end = ob.start + b_size;
- break;
-
- case 'top':
- ob.start = Math.max(rownum - b_size, 1);
- ob.end = rownum;
- break;
-
- default:
- ob.start = Math.max(rownum - this._lookbehind(), 1);
- ob.end = ob.start + b_size;
- break;
- }
-
- return ob;
- },
-
- _lookbehind: function()
- {
- return parseInt(0.4 * this.bufferSize(), 10);
- },
-
- // args = (object) The list of parameters.
- // opts = (object) [noslice, view]
- // Returns a Hash object
- addRequestParams: function(args, opts)
- {
- opts = opts || {};
- var cid = this.getMetaData('cacheid', opts.view),
- cached, params, rowlist;
-
- params = this.opts.onAjaxRequest
- ? this.opts.onAjaxRequest(opts.view || this.view)
- : $H();
-
- params.update({ view: opts.view || this.view });
-
- if (cid) {
- params.update({ cacheid: cid });
- }
-
- if (!opts.noslice) {
- rowlist = this._getSliceBounds(this.currentOffset(), null, opts.view);
- params.update({ slice: rowlist.start + ':' + rowlist.end });
- }
-
- if (this.opts.onCachedList) {
- cached = this.opts.onCachedList(opts.view || this.view);
- } else {
- cached = this._getBuffer(opts.view).getAllUIDs();
- cached = cached.size()
- ? cached.toJSON()
- : '';
- }
-
- if (cached.length) {
- params.update({ cached: cached });
- }
-
- return params.merge(args);
- },
-
- // params - (object) A list of parameters to send to server
- // opts - (object) Args to pass to addRequestParams().
- _ajaxRequest: function(params, other)
- {
- new Ajax.Request(this.opts.ajax_url, Object.extend(this.opts.ajax_opts || {}, {
- evalJS: false,
- evalJSON: true,
- onComplete: this.ajax_response,
- parameters: this.addRequestParams(params, other)
- }));
- },
-
- _ajaxRequestComplete: function(r)
- {
- if (r.responseJSON) {
- this.parseJSONResponse(r.responseJSON);
- }
- },
-
- // r - (object) responseJSON returned from the server.
- parseJSONResponse: function(r)
- {
- if (!r.ViewPort) {
- return;
- }
-
- r = r.ViewPort;
-
- if (r.rangelist) {
- this.select(this.createSelection('uid', r.rangelist, r.view));
- if (this.opts.onEndFetch) {
- this.opts.onEndFetch();
- }
- }
-
- if (r.cacheid) {
- this._ajaxResponse(r);
- }
- },
-
- // r = (Object) viewport response object
- _ajaxResponse: function(r)
- {
- if (this.isbusy) {
- this._ajaxResponse.bind(this, r).defer();
- return;
- }
-
- this.isbusy = true;
- this._clearWait();
-
- var offset,
- buffer = this._getBuffer(r.view),
- llist = buffer.getMetaData('llist') || $H();
-
- buffer.update(Object.isArray(r.data) ? {} : r.data, Object.isArray(r.rowlist) ? {} : r.rowlist, r.metadata || {}, { reset: r.reset, resetmd: r.resetmd, update: r.update });
-
- llist.unset(r.request_id);
-
- buffer.setMetaData({
- cacheid: r.cacheid,
- label: r.label,
- llist: llist,
- total_rows: r.totalrows
- }, true);
-
- if (this.opts.onCacheUpdate) {
- this.opts.onCacheUpdate(r.view);
- }
-
- if (r.request_id &&
- r.request_id == this.active_req) {
- this.active_req = null;
- offset = buffer.getMetaData('req_offset');
- buffer.setMetaData({ req_offset: undefined });
-
- if (this.opts.onEndFetch) {
- this.opts.onEndFetch();
- }
- }
-
- // TODO: Flag for no _fetchBuffer()?
- if (this.view == r.view) {
- this._updateContent(Object.isUndefined(offset) ? (r.rownum ? Number(r.rownum) - 1 : this.currentOffset()) : offset);
- }
-
- this.isbusy = false;
- },
-
- // offset = (integer) TODO
- // opts = (object) TODO [background, view]
- _updateContent: function(offset, opts)
- {
- opts = opts || {};
-
- if (!this._getBuffer(opts.view).sliceLoaded(offset)) {
- opts.offset = offset;
- this._fetchBuffer(opts);
- return false;
- }
-
- var c = this.opts.content,
- c_nodes = [],
- page_size = this.getPageSize(),
- rows;
-
- if (this.opts.onClear) {
- this.opts.onClear(this.visibleRows());
- }
-
- this.scroller.updateSize();
- this.scrollTo(offset + 1, { noupdate: true, top: true });
-
- offset = this.currentOffset();
- rows = this.createSelection('rownum', $A($R(offset + 1, offset + page_size)));
-
- if (rows.size()) {
- c_nodes = rows.get('dataob');
- c.update(c_nodes.collect(this.prepareRow.bind(this)).join(''));
- } else {
- c.update(this.empty_msg);
- }
-
- if (this.opts.onContentComplete) {
- this.opts.onContentComplete(c_nodes);
- }
-
- return true;
- },
-
- prepareRow: function(row)
- {
- var r = Object.clone(row);
-
- r.bg = r.bg
- ? row.bg.clone()
- : [];
-
- if (this.getSelected().contains('uid', r.vp_id)) {
- r.bg.push('vpRowSelected');
- }
-
- r.bg.unshift('vpRow');
-
- if (this.opts.onContent) {
- this.opts.onContent(r);
- }
-
- // Mandatory DOM ID and class information.
- r.vpData = 'id="' + r.domid + '" class="' + r.bg.join(' ') + '"';
-
- return this.template.evaluate(r);
- },
-
- updateRow: function(row)
- {
- var d = $(row.domid);
- if (d) {
- if (this.opts.onClear) {
- this.opts.onClear([ d ]);
- }
-
- d.replace(this.prepareRow(row));
-
- if (this.opts.onContentComplete) {
- this.opts.onContentComplete([ row ]);
- }
- }
-
- },
-
- _handleWait: function(call)
- {
- this._clearWait();
-
- // Server did not respond in defined amount of time. Alert the
- // callback function and set the next timeout.
- if (call && this.opts.onWait) {
- this.opts.onWait();
- }
-
- // Call wait handler every x seconds
- if (this.opts.viewport_wait) {
- this.waitHandler = this._handleWait.bind(this, true).delay(this.opts.viewport_wait);
- }
- },
-
- _clearWait: function()
- {
- if (this.waitHandler) {
- clearTimeout(this.waitHandler);
- this.waitHandler = null;
- }
- },
-
- visibleRows: function()
- {
- return this.opts.content.childElements();
- },
-
- getMetaData: function(id, view)
- {
- return this._getBuffer(view).getMetaData(id);
- },
-
- setMetaData: function(vals, view)
- {
- this._getBuffer(view).setMetaData(vals, false);
- },
-
- _getBuffer: function(view, create)
- {
- view = view || this.view;
-
- return (!create && this.views[view])
- ? this.views[view]
- : new ViewPort_Buffer(this, view);
- },
-
- currentOffset: function()
- {
- return this.scroller.currentOffset();
- },
-
- _getLineHeight: function()
- {
- if (!this.line_height) {
- // To avoid hardcoding the line height, create a temporary row to
- // figure out what the CSS says.
- var d = new Element('DIV', { className: this.opts.content_class }).insert(new Element('DIV', { className: 'vpRow' })).hide();
- $(document.body).insert(d);
- this.line_height = d.getHeight();
- d.remove();
- }
-
- return this.line_height;
- },
-
- // (type) = (string) [null (DEFAULT), 'current', 'default', 'max']
- getPageSize: function(type)
- {
- switch (type) {
- case 'current':
- return Math.min(this.page_size, this.getMetaData('total_rows'));
-
- case 'default':
- return Math.max(parseInt(this.getPageSize('max') * 0.45), 5);
-
- case 'max':
- case 'splitmax':
- return parseInt((this._getMaxHeight() - (type == 'max' ? 0 : 100)) / this._getLineHeight());
-
- default:
- return this.page_size;
- }
- },
-
- _getMaxHeight: function()
- {
- return document.viewport.getHeight() - this.opts.content.viewportOffset()[1];
- },
-
- bufferSize: function()
- {
- // Buffer size must be at least the maximum page size.
- return Math.round(Math.max(this.getPageSize('max') + 1, this.opts.buffer_pages * this.getPageSize()));
- },
-
- limitTolerance: function()
- {
- return Math.round(this.bufferSize() * (this.opts.limit_factor / 100));
- },
-
- showSplitPane: function(show)
- {
- this.show_split_pane = show;
- this.onResize(true);
- },
-
- _initSplitBar: function()
- {
- if (this.split_bar) {
- return;
- }
-
- this.split_bar = $(this.opts.split_bar);
- new Drag(this.split_bar, {
- constraint: 'vertical',
- ghosting: true,
- nodrop: true,
- onStart: function() {
- // Cache these values since we will be using them multiple
- // times in snap().
- this.sp = {
- lh: this._getLineHeight(),
- lines: this.page_size,
- max: this.getPageSize('splitmax'),
- orig: this.page_size,
- pos: $(this.opts.content).positionedOffset()[1]
- };
- }.bind(this),
- snap: function(x, y, elt) {
- var l = parseInt((y - this.sp.pos) / this.sp.lh);
- if (l < 1) {
- l = 1;
- } else if (l > this.sp.max) {
- l = this.sp.max;
- }
- this.sp.lines = l;
- return [ x, this.sp.pos + (l * this.sp.lh) ];
- }.bind(this),
- onEnd: function() {
- this.page_size = this.sp.lines;
- this.onResize(true);
- if (this.opts.onSplitBarChange &&
- this.sp.orig != this.sp.lines) {
- this.opts.onSplitBarChange();
- }
- }.bind(this)
- });
- this.split_bar.observe('dblclick', function() {
- var old_size = this.page_size;
- this.page_size = this.getPageSize('default');
- this._onResize(true);
- if (this.opts.onSplitBarChange &&
- old_size != this.page_size) {
- this.opts.onSplitBarChange();
- }
- }.bind(this));
- },
-
- createSelection: function(format, data, view)
- {
- var buffer = this._getBuffer(view);
- return buffer ? new ViewPort_Selection(buffer, format, data) : new ViewPort_Selection(this._getBuffer(this.view));
- },
-
- getSelection: function(view)
- {
- var buffer = this._getBuffer(view);
- return this.createSelection('uid', buffer ? buffer.getAllUIDs() : [], view);
- },
-
- // vs = (Viewport_Selection | array) A Viewport_Selection object -or-, if
- // opts.range is set, an array of row numbers.
- // opts = (object) TODO [add, range]
- select: function(vs, opts)
- {
- opts = opts || {};
-
- var b = this._getBuffer(),
- sel, slice;
-
- if (opts.range) {
- slice = this.createSelection('rownum', vs);
- if (vs.size() != slice.size()) {
- if (this.opts.onFetch) {
- this.opts.onFetch();
- }
-
- this._ajaxRequest({ rangeslice: 1, slice: vs.min() + ':' + vs.size() });
- return;
- }
- vs = slice;
- }
-
- if (!opts.add) {
- sel = this.getSelected();
- b.deselect(sel, true);
- sel.get('div').invoke('removeClassName', 'vpRowSelected');
- }
- b.select(vs);
- vs.get('div').invoke('addClassName', 'vpRowSelected');
- if (this.opts.onSelect) {
- this.opts.onSelect(vs, opts);
- }
- },
-
- // vs = (Viewport_Selection) A Viewport_Selection object.
- // opts = (object) TODO [clearall]
- deselect: function(vs, opts)
- {
- opts = opts || {};
-
- if (vs.size() &&
- this._getBuffer().deselect(vs, opts && opts.clearall)) {
- vs.get('div').invoke('removeClassName', 'vpRowSelected');
- if (this.opts.onDeselect) {
- this.opts.onDeselect(vs, opts)
- }
- }
- },
-
- getSelected: function()
- {
- return Object.clone(this._getBuffer().getSelected());
- }
-
-}),
-
-/**
- * ViewPort_Scroller
- */
-ViewPort_Scroller = Class.create({
- // Variables initialized to undefined: noupdate
-
- initialize: function(vp)
- {
- this.vp = vp;
- },
-
- _createScrollBar: function()
- {
- if (this.scrollDiv) {
- return false;
- }
-
- var c = this.vp.opts.content;
-
- // Create the outer div.
- this.scrollDiv = new Element('DIV', { className: 'sbdiv' }).setStyle({ height: c.getHeight() + 'px' }).hide();
-
- // Add scrollbar to parent viewport and give our parent a right
- // margin just big enough to accomodate the scrollbar.
- c.insert({ after: this.scrollDiv }).setStyle({ marginRight: '-' + this.scrollDiv.getWidth() + 'px' });
-
- // Create scrollbar object.
- this.scrollbar = new DimpSlider(this.scrollDiv, {
- buttonclass: { up: 'sbup', down: 'sbdown' },
- cursorclass: 'sbcursor',
- onChange: this._onScroll.bind(this),
- onSlide: this.vp.opts.onSlide ? this.vp.opts.onSlide : null,
- pagesize: this.vp.getPageSize(),
- totalsize: this.vp.getMetaData('total_rows')
- });
-
- // Mouse wheel handler.
- c.observe(Prototype.Browser.Gecko ? 'DOMMouseScroll' : 'mousewheel', function(e) {
- var move_num = Math.min(this.vp.getPageSize(), 3);
- this.moveScroll(this.currentOffset() + ((e.wheelDelta >= 0 || e.detail < 0) ? (-1 * move_num) : move_num));
- }.bindAsEventListener(this));
-
- return true;
- },
-
- onResize: function()
- {
- if (!this.scrollDiv) {
- return;
- }
-
- // Update the container div.
- this.scrollsize = this.vp.opts.content.getHeight();
- this.scrollDiv.setStyle({ height: this.scrollsize + 'px' });
-
- // Update the scrollbar size
- this.updateSize();
-
- // Update displayed content.
- this.vp.requestContentRefresh(this.currentOffset());
- },
-
- updateSize: function()
- {
- if (!this._createScrollBar()) {
- this.scrollbar.updateHandleLength(this.vp.getPageSize(), this.vp.getMetaData('total_rows'));
- }
- },
-
- clear: function()
- {
- if (this.scrollDiv) {
- this.scrollbar.updateHandleLength(0, 0);
- }
- },
-
- // offset = (integer) Offset to move the scrollbar to
- moveScroll: function(offset)
- {
- this._createScrollBar();
- this.scrollbar.setScrollPosition(offset);
- },
-
- _onScroll: function()
- {
- if (!this.noupdate) {
- this.vp.requestContentRefresh(this.currentOffset());
- }
- },
-
- currentOffset: function()
- {
- return this.scrollbar ? this.scrollbar.getValue() : 0;
- }
-
-}),
-
-/**
- * ViewPort_Buffer
- *
- * Note: recognize the difference between offset (current location in the
- * viewport - starts at 0) with start parameters (the row numbers - starts
- * at 1).
- */
-ViewPort_Buffer = Class.create({
-
- initialize: function(vp, view)
- {
- this.vp = vp;
- this.view = view;
- this.clear();
- },
-
- getView: function()
- {
- return this.view;
- },
-
- // d = (object) Data
- // l = (object) Rowlist
- // md = (object) User defined metadata
- // opts = (object) TODO [reset, resetmd, update]
- update: function(d, l, md, opts)
- {
- var val;
- d = $H(d);
- l = $H(l);
- opts = opts || {};
-
- if (!opts.reset && this.data.size()) {
- this.data.update(d);
- } else {
- this.data = d;
- }
-
- if (opts.update || opts.reset) {
- this.uidlist = l;
- this.rowlist = $H();
- } else {
- this.uidlist = this.uidlist.size() ? this.uidlist.merge(l) : l;
- }
-
- l.each(function(o) {
- this.rowlist.set(o.value, o.key);
- }, this);
-
- if (opts.resetmd) {
- this.usermdata = $H(md);
- } else {
- $H(md).each(function(pair) {
- if (Object.isString(pair.value) || Object.isNumber(pair.value)) {
- this.usermdata.set(pair.key, pair.value);
- } else {
- val = this.usermdata.get(pair.key);
- if (val) {
- this.usermdata.get(pair.key).update($H(pair.value));
- } else {
- this.usermdata.set(pair.key, $H(pair.value));
- }
- }
- }, this);
- }
- },
-
- // offset = (integer) Offset of the beginning of the slice.
- // rows = (array) Additional rows to include in the search.
- sliceLoaded: function(offset, rows)
- {
- var range = $A($R(offset + 1, Math.min(offset + this.vp.getPageSize() - 1, this.getMetaData('total_rows'))));
-
- return rows
- ? (range.diff(this.rowlist.keys().concat(rows)).size() == 0)
- : !this._rangeCheck(range);
- },
-
- isNearingLimit: function(offset)
- {
- if (this.uidlist.size() != this.getMetaData('total_rows')) {
- if (offset != 0 &&
- this._rangeCheck($A($R(Math.max(offset + 1 - this.vp.limitTolerance(), 1), offset)))) {
- return 'top';
- } else if (this._rangeCheck($A($R(offset + 1, Math.min(offset + this.vp.limitTolerance() + this.vp.getPageSize() - 1, this.getMetaData('total_rows')))).reverse())) {
- // Search for missing messages in reverse order since in
- // normal usage (sequential scrolling through the message
- // list) messages are more likely to be missing at furthest
- // from the current view.
- return 'bottom';
- }
- }
-
- return false;
- },
-
- _rangeCheck: function(range)
- {
- return !range.all(this.rowlist.get.bind(this.rowlist));
- },
-
- getData: function(uids)
- {
- return uids.collect(function(u) {
- var e = this.data.get(u);
- if (!Object.isUndefined(e)) {
- // We can directly write the rownum to the original object
- // since we will always rewrite when creating rows.
- e.domid = 'vp_row' + u;
- e.rownum = this.uidlist.get(u);
- e.vp_id = u;
- return e;
- }
- }, this).compact();
- },
-
- getAllUIDs: function()
- {
- return this.uidlist.keys();
- },
-
- getAllRows: function()
- {
- return this.rowsToUIDs(this.rowlist.keys());
- },
-
- rowsToUIDs: function(rows)
- {
- return rows.collect(this.rowlist.get.bind(this.rowlist)).compact();
- },
-
- // vs = (Viewport_Selection) TODO
- select: function(vs)
- {
- this.selected.add('uid', vs.get('uid'));
- },
-
- // vs = (Viewport_Selection) TODO
- // clearall = (boolean) Clear all entries?
- deselect: function(vs, clearall)
- {
- var size = this.selected.size();
-
- if (clearall) {
- this.selected.clear();
- } else {
- this.selected.remove('uid', vs.get('uid'));
- }
- return size != this.selected.size();
- },
-
- getSelected: function()
- {
- return this.selected;
- },
-
- // rownums = (array) Array of row numbers to remove.
- remove: function(rownums)
- {
- var minrow = rownums.min(),
- rowsize = this.rowlist.size(),
- rowsubtract = 0,
- newsize = rowsize - rownums.size();
-
- return this.rowlist.keys().each(function(n) {
- if (n >= minrow) {
- var id = this.rowlist.get(n), r;
- if (rownums.include(n)) {
- this.data.unset(id);
- this.uidlist.unset(id);
- rowsubtract++;
- } else if (rowsubtract) {
- r = n - rowsubtract;
- this.rowlist.set(r, id);
- this.uidlist.set(id, r);
- }
- if (n > newsize) {
- this.rowlist.unset(n);
- }
- }
- }, this);
- },
-
- clear: function()
- {
- this.data = $H();
- this.mdata = $H({ total_rows: 0 });
- this.rowlist = $H();
- this.selected = new ViewPort_Selection(this);
- this.uidlist = $H();
- this.usermdata = $H();
- },
-
- getMetaData: function(id)
- {
- return this.mdata.get(id) || this.usermdata.get(id);
- },
-
- setMetaData: function(vals, priv)
- {
- if (priv) {
- this.mdata.update(vals);
- } else {
- this.usermdata.update(vals);
- }
- }
-
-}),
-
-/**
- * ViewPort_Selection
- */
-ViewPort_Selection = Class.create({
-
- // Define property to aid in object detection
- viewport_selection: true,
-
- // Formats:
- // 'dataob' = Data objects
- // 'div' = DOM DIVs
- // 'domid' = DOM IDs
- // 'rownum' = Row numbers
- // 'uid' = Unique IDs
- initialize: function(buffer, format, data)
- {
- this.buffer = buffer;
- this.clear();
- if (!Object.isUndefined(format)) {
- this.add(format, data);
- }
- },
-
- add: function(format, d)
- {
- var c = this._convert(format, d);
- this.data = this.data.size() ? this.data.concat(c).uniq() : c;
- },
-
- remove: function(format, d)
- {
- this.data = this.data.diff(this._convert(format, d));
- },
-
- _convert: function(format, d)
- {
- d = Object.isArray(d) ? d : [ d ];
-
- switch (format) {
- case 'dataob':
- return d.pluck('vp_id');
-
- case 'div':
- return d.pluck('id').invoke('substring', 6);
-
- case 'domid':
- return d.invoke('substring', 6);
-
- case 'rownum':
- return this.buffer.rowsToUIDs(d);
-
- case 'uid':
- return d;
- }
- },
-
- clear: function()
- {
- this.data = [];
- },
-
- get: function(format)
- {
- format = Object.isUndefined(format) ? 'uid' : format;
- if (format == 'uid') {
- return this.data;
- }
- var d = this.buffer.getData(this.data);
-
- switch (format) {
- case 'dataob':
- return d;
-
- case 'div':
- return d.pluck('domid').collect(function(e) { return $(e); }).compact();
-
- case 'domid':
- return d.pluck('domid');
-
- case 'rownum':
- return d.pluck('rownum');
- }
- },
-
- contains: function(format, d)
- {
- return this.data.include(this._convert(format, d).first());
- },
-
- // params = (Object) Key is search key, value is object -> key of object
- // must be the following:
- // equal - Matches any value contained in the query array.
- // not - Matches any value not contained in the query array.
- // regex - Matches the RegExp contained in the query.
- search: function(params)
- {
- return new ViewPort_Selection(this.buffer, 'uid', this.get('dataob').findAll(function(i) {
- // i = data object
- return $H(params).all(function(k) {
- // k.key = search key; k.value = search criteria
- return $H(k.value).all(function(s) {
- // s.key = search type; s.value = search query
- switch (s.key) {
- case 'equal':
- case 'not':
- var r = i[k.key] && s.value.include(i[k.key]);
- return (s.key == 'equal') ? r : !r;
-
- case 'regex':
- return i[k.key].match(s.value);
- }
- });
- });
- }).pluck('vp_id'));
- },
-
- size: function()
- {
- return this.data.size();
- },
-
- set: function(vals)
- {
- this.get('dataob').each(function(d) {
- $H(vals).each(function(v) {
- d[v.key] = v.value;
- });
- });
- },
-
- getBuffer: function()
- {
- return this.buffer;
- }
-
-});
-
-/** Utility Functions **/
-Object.extend(Array.prototype, {
- // Need our own diff() function because prototypejs's without() function
- // does not handle array input.
- diff: function(values)
- {
- return this.select(function(value) {
- return !values.include(value);
- });
- },
- numericSort: function()
- {
- return this.collect(Number).sort(function(a, b) {
- return (a > b) ? 1 : ((a < b) ? -1 : 0);
- });
- }
-});
+++ /dev/null
-/**
- * Provides the javascript for the acl.php script (standard view).
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var ImpAcl = {
-
- acl_loading: false,
-
- folderChange: function(e, clear)
- {
- if ($F('aclfolder')) {
- if (!this.acl_loading || clear != null) {
- this.acl_loading = true;
- $('acl').disable();
- $('folders').submit();
- e.stop();
- }
- }
- },
-
- changeHandler: function(e)
- {
- switch (e.element().readAttribute('id')) {
- case 'aclfolder':
- this.folderChange(e);
- break;
- }
- },
-
- clickHandler: function(e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = e.element();
-
- while (Object.isElement(elt)) {
- switch (elt.readAttribute('id')) {
- case 'changefolder':
- case 'resetbut':
- this.folderChange(e, true);
- break;
- }
-
- elt = elt.up();
- }
- }
-
-};
-
-document.observe('change', ImpAcl.changeHandler.bindAsEventListener(ImpAcl));
-document.observe('click', ImpAcl.clickHandler.bindAsEventListener(ImpAcl));
+++ /dev/null
-/**
- * compose.js - Javascript code used in the DIMP compose view.
- *
- * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var DimpCompose = {
- // Variables defaulting to empty/false:
- // auto_save_interval, button_pressed, compose_cursor, dbtext,
- // drafts_mbox, editor_on, mp_padding, resizebcc, resizecc, resizeto,
- // row_height, sbtext, skip_spellcheck, spellcheck, uploading
- last_msg: '',
- textarea_ready: true,
-
- confirmCancel: function()
- {
- if (window.confirm(DIMP.text_compose.cancel)) {
- DimpCore.doAction(DIMP.conf_compose.auto_save_interval_val ? 'DeleteDraft' : 'CancelCompose', { imp_compose: $F('composeCache') });
- this.updateDraftsMailbox();
- return this.closeCompose();
- }
- },
-
- updateDraftsMailbox: function()
- {
- if (DIMP.baseWindow.DimpBase &&
- DIMP.baseWindow.DimpBase.folder == DIMP.conf_compose.drafts_mbox) {
- DIMP.baseWindow.DimpBase.poll();
- }
- },
-
- closeCompose: function()
- {
- if (DIMP.conf_compose.qreply) {
- this.closeQReply();
- } else if (DIMP.baseWindow.DimpBase || DIMP.conf_compose.popup) {
- DimpCore.closePopup();
- } else {
- DimpCore.redirect(DIMP.conf.URI_DIMP);
- }
- },
-
- closeQReply: function()
- {
- var al = $('attach_list').childElements();
- this.last_msg = '';
-
- if (al.size()) {
- this.removeAttach(al);
- }
-
- $('composeCache').setValue('');
- $('qreply', 'sendcc', 'sendbcc').invoke('hide');
- [ $('msgData'), $('togglecc').up(), $('togglebcc').up() ].invoke('show');
- if (this.editor_on) {
- this.toggleHtmlEditor();
- }
- $('compose').reset();
-
- // Disable auto-save-drafts now.
- if (this.auto_save_interval) {
- this.auto_save_interval.stop();
- }
- },
-
- change_identity: function()
- {
- var lastSignature, msg, nextSignature, pos,
- id = $F('identity'),
- last = this.get_identity($F('last_identity')),
- msgval = $('message'),
- next = this.get_identity(id),
- ssm = $('save_sent_mail');
-
- $('sent_mail_folder_label').setText(next.id[5]);
- $('bcc').setValue(next.id[6]);
- if (ssm) {
- ssm.writeAttribute('checked', next.id[4]);
- }
-
- // Finally try and replace the signature.
- if (this.editor_on) {
- msg = FCKeditorAPI.GetInstance('message').GetHTML().replace(/\r\n/g, '\n');
- lastSignature = '<p><!--begin_signature--><!--end_signature--></p>';
- nextSignature = '<p><!--begin_signature-->' + next.sig.replace(/^ ?<br \/>\n/, '').replace(/ +/g, ' ') + '<!--end_signature--></p>';
-
- // Dot-all functionality achieved with [\s\S], see:
- // http://simonwillison.net/2004/Sep/20/newlines/
- msg = msg.replace(/<p>\s*<!--begin_signature-->[\s\S]*?<!--end_signature-->\s*<\/p>/, lastSignature);
- } else {
- msg = $F(msgval).replace(/\r\n/g, '\n');
- lastSignature = last.sig;
- nextSignature = next.sig;
- }
-
- pos = (last.id[2])
- ? msg.indexOf(lastSignature)
- : msg.lastIndexOf(lastSignature);
-
- if (pos != -1) {
- if (next.id[2] == last.id[2]) {
- msg = msg.substring(0, pos) + nextSignature + msg.substring(pos + lastSignature.length, msg.length);
- } else if (next.id[2]) {
- msg = nextSignature + msg.substring(0, pos) + msg.substring(pos + lastSignature.length, msg.length);
- } else {
- msg = msg.substring(0, pos) + msg.substring(pos + lastSignature.length, msg.length) + nextSignature;
- }
-
- msg = msg.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');
- if (this.editor_on) {
- FCKeditorAPI.GetInstance('message').SetHTML(msg);
- } else {
- msgval.setValue(msg);
- }
- $('last_identity').setValue(id);
- }
- },
-
- get_identity: function(id, editor_on)
- {
- editor_on = Object.isUndefined(editor_on) ? this.editor_on : editor_on;
- return {
- id: DIMP.conf_compose.identities[id],
- sig: DIMP.conf_compose.identities[id][(editor_on ? 1 : 0)].replace(/^\n/, '')
- };
- },
-
- uniqueSubmit: function(action)
- {
- var db, params, sb,
- c = $('compose');
-
- if (DIMP.SpellCheckerObject &&
- DIMP.SpellCheckerObject.isActive()) {
- DIMP.SpellCheckerObject.resume();
- this.skip_spellcheck = true;
- if (!this.textarea_ready) {
- this.uniqueSubmit.bind(this, action).defer();
- return;
- }
- }
-
- if (action == 'send_message' || action == 'save_draft') {
- this.button_pressed = true;
-
- switch (action) {
- case 'send_message':
- if (($F('subject') == '') &&
- !window.confirm(DIMP.text_compose.nosubject)) {
- return;
- }
-
- if (!this.skip_spellcheck &&
- DIMP.conf_compose.spellcheck &&
- DIMP.SpellCheckerObject &&
- !DIMP.SpellCheckerObject.isActive()) {
- DIMP.SpellCheckerObject.spellCheck(this.onNoSpellError.bind(this, action));
- return;
- }
-
- if (!this.sbtext) {
- sb = $('send_button');
- this.sbtext = sb.getText();
- sb.setText(DIMP.text_compose.sending);
- }
- break;
-
- case 'save_draft':
- if (!this.dbtext) {
- db = $('draft_button');
- this.dbtext = db.getText();
- db.setText(DIMP.text_compose.saving);
- }
- break;
- }
-
- // Don't send/save until uploading is completed.
- if (this.uploading) {
- (function() { if (this.button_pressed) { this.uniqueSubmit(action); } }).bind(this).delay(0.25);
- return;
- }
- }
-
- c.setStyle({ cursor: 'wait' });
- this.skip_spellcheck = false;
- $('action').setValue(action);
-
- if (action == 'add_attachment') {
- // We need a submit action here because browser security models
- // won't let us access files on user's filesystem otherwise.
- this.uploading = true;
- c.submit();
- } else {
- // Move HTML text to textarea field for submission.
- if (this.editor_on) {
- FCKeditorAPI.GetInstance('message').UpdateLinkedField();
- }
-
- // Use an AJAX submit here so that we can do javascript-y stuff
- // before having to close the window on success.
- params = c.serialize(true);
- if (!DIMP.baseWindow.DimpBase) {
- params.nonotify = true;
- }
- DimpCore.doAction('*' + DIMP.conf.URI_COMPOSE, params, null, this.uniqueSubmitCallback.bind(this));
- }
- },
-
- uniqueSubmitCallback: function(r)
- {
- var elt,
- d = r.response;
-
- if (!d) {
- return;
- }
-
- if (d.imp_compose) {
- $('composeCache').setValue(d.imp_compose);
- }
-
- if (d.success || d.action == 'add_attachment') {
- switch (d.action) {
- case 'auto_save_draft':
- case 'save_draft':
- this.button_pressed = false;
-
- this.updateDraftsMailbox();
-
- if (d.action == 'save_draft') {
- if (DIMP.baseWindow.DimpBase && !DIMP.conf_compose.qreply) {
- DIMP.baseWindow.DimpCore.showNotifications(r.msgs);
- }
- if (DIMP.conf_compose.close_draft) {
- return this.closeCompose();
- }
- }
- break;
-
- case 'send_message':
- this.button_pressed = false;
- if (DIMP.baseWindow.DimpBase) {
- if (d.reply_type) {
- DIMP.baseWindow.DimpBase.flag(d.reply_type == 'reply' ? '\\answered' : '$forwarded', true, { index: d.index, mailbox: d.reply_folder, noserver: true });
- }
-
- // @TODO: Needed?
- if (d.folder) {
- DIMP.baseWindow.DimpBase.createFolder(d.folder);
- }
-
- if (d.draft_delete) {
- DIMP.baseWindow.DimpBase.poll();
- }
-
- if (d.log) {
- DIMP.baseWindow.DimpBase.updateMsgLog(d.log, { index: d.index, mailbox: d.reply_folder });
- }
-
- if (!DIMP.conf_compose.qreply) {
- DIMP.baseWindow.DimpCore.showNotifications(r.msgs);
- }
- }
- return this.closeCompose();
-
- case 'add_attachment':
- this.uploading = false;
- if (d.success) {
- this.addAttach(d.info.number, d.info.name, d.info.type, d.info.size);
- } else {
- this.button_pressed = false;
- }
- if (DIMP.conf_compose.attach_limit != -1 &&
- $('attach_list').childElements().size() > DIMP.conf_compose.attach_limit) {
- $('upload').writeAttribute('disabled', false);
- elt = new Element('DIV', [ DIMP.text_compose.atc_limit ]);
- } else {
- elt = new Element('INPUT', { type: 'file', name: 'file_1' });
- }
- $('upload_wait').replace(elt.writeAttribute('id', 'upload'));
- this.resizeMsgArea();
- break;
- }
- } else {
- this.button_pressed = false;
- }
-
- $('compose').setStyle({ cursor: null });
-
- // Re-enable buttons if needed.
- if (!this.button_pressed) {
- if (this.sbtext) {
- $('send_button').setText(this.sbtext);
- }
- if (this.dbtext) {
- $('draft_button').setText(this.dbtext);
- }
- this.dbtext = this.sbtext = null;
- }
-
- if (!r.msgs_noauto) {
- DimpCore.showNotifications(r.msgs);
- }
- },
-
- onNoSpellError: function(action)
- {
- this.skip_spellcheck = true;
- this.uniqueSubmit(action);
- },
-
- toggleHtmlEditor: function(noupdate)
- {
- if (!DIMP.conf_compose.rte_avail) {
- return;
- }
- noupdate = noupdate || false;
- if (DIMP.SpellCheckerObject) {
- DIMP.SpellCheckerObject.resume();
- }
-
- var text;
-
- if (this.editor_on) {
- this.editor_on = false;
-
- text = FCKeditorAPI.GetInstance('message').GetHTML();
- $('messageParent').childElements().invoke('hide');
- $('message').show();
-
- DimpCore.doAction('Html2Text', { text: text }, null, this.setMessageText.bind(this), { asynchronous: false });
- } else {
- this.editor_on = true;
- if (!noupdate) {
- DimpCore.doAction('Text2Html', { text: $F('message') }, null, this.setMessageText.bind(this), { asynchronous: false });
- }
-
- oFCKeditor.Height = this.getMsgAreaHeight();
- // Try to reuse the old fckeditor instance.
- try {
- FCKeditorAPI.GetInstance('message').SetHTML($F('message'));
- $('messageParent').childElements().invoke('show');
- $('message').hide();
- } catch (e) {
- this.RTELoading('show');
- FCKeditor_OnComplete = this.RTELoading.curry('hide');
- oFCKeditor.ReplaceTextarea();
- }
- }
- $('htmlcheckbox').checked = this.editor_on;
- $('html').setValue(this.editor_on ? 1 : 0);
- },
-
- RTELoading: function(cmd)
- {
- var o, r;
- if (!$('rteloading')) {
- r = new Element('DIV', { id: 'rteloading' }).clonePosition($('messageParent'));
- $(document.body).insert(r);
- o = r.viewportOffset();
- $(document.body).insert(new Element('SPAN', { id: 'rteloadingtxt' }).setStyle({ top: (o.top + 15) + 'px', left: (o.left + 15) + 'px' }).insert(DIMP.text.loading));
- }
- $('rteloading', 'rteloadingtxt').invoke(cmd);
- },
-
- toggleHtmlCheckbox: function()
- {
- if (!this.editor_on || window.confirm(DIMP.text_compose.toggle_html)) {
- this.toggleHtmlEditor();
- }
- },
-
- getMsgAreaHeight: function()
- {
- return document.viewport.getHeight() - $('messageParent').cumulativeOffset()[1] - this.mp_padding;
- },
-
- initializeSpellChecker: function()
- {
- if (!DIMP.conf_compose.rte_avail) {
- return;
- }
-
- if (typeof DIMP.SpellCheckerObject != 'object') {
- // If we fired before the onload that initializes the spellcheck,
- // wait.
- this.initializeSpellChecker.bind(this).defer();
- return;
- }
-
- DIMP.SpellCheckerObject.onBeforeSpellCheck = function() {
- if (!this.editor_on) {
- return;
- }
- DIMP.SpellCheckerObject.htmlAreaParent = 'messageParent';
- DIMP.SpellCheckerObject.htmlArea = $('message').adjacent('iframe[id*=message]').first();
- $('message').setValue(FCKeditorAPI.GetInstance('message').GetHTML());
- this.textarea_ready = false;
- }.bind(this);
- DIMP.SpellCheckerObject.onAfterSpellCheck = function() {
- if (!this.editor_on) {
- return;
- }
- DIMP.SpellCheckerObject.htmlArea = DIMP.SpellCheckerObject.htmlAreaParent = null;
- var ed = FCKeditorAPI.GetInstance('message');
- ed.SetHTML($F('message'));
- ed.Events.AttachEvent('OnAfterSetHTML', function() { this.textarea_ready = true; }.bind(this));
- }.bind(this);
- },
-
- setMessageText: function(r)
- {
- var ta = $('message');
- if (!ta) {
- $('messageParent').insert(new Element('TEXTAREA', { id: 'message', name: 'message', style: 'width:100%;' }).insert(r.response.text));
- } else {
- ta.setValue(r.response.text);
- }
-
- if (!this.editor_on) {
- this.resizeMsgArea();
- }
- },
-
- fillForm: function(msg, header, focus, noupdate)
- {
- // On IE, this can get loaded before DOM;loaded. Check for an init
- // value and don't load until it is available.
- if (!this.resizeto) {
- this.fillForm.bind(this, msg, header, focus, noupdate).defer();
- return;
- }
-
- var bcc_add, fo,
- identity = this.get_identity($F('last_identity')),
- msgval = $('message');
-
- if (!this.last_msg.empty() &&
- this.last_msg != $F(msgval).replace(/\r/g, '') &&
- !window.confirm(DIMP.text_compose.fillform)) {
- return;
- }
-
- // Set auto-save-drafts now if not already active.
- if (DIMP.conf_compose.auto_save_interval_val &&
- !this.auto_save_interval) {
- this.auto_save_interval = new PeriodicalExecuter(function() {
- var cur_msg = this.editor_on
- ? FCKeditorAPI.GetInstance('message').GetHTML()
- : $F(msgval);
- cur_msg = cur_msg.replace(/\r/g, '');
- if (!cur_msg.empty() && this.last_msg != cur_msg) {
- this.uniqueSubmit('auto_save_draft');
- this.last_msg = cur_msg;
- }
- }.bind(this), DIMP.conf_compose.auto_save_interval_val * 60);
- }
-
- if (this.editor_on) {
- fo = FCKeditorAPI.GetInstance('message');
- fo.SetHTML(msg);
- this.last_msg = fo.GetHTML().replace(/\r/g, '');
- } else {
- msgval.setValue(msg);
- this.setCursorPosition(msgval);
- this.last_msg = $F(msgval).replace(/\r/g, '');
- }
-
- $('to').setValue(header.to);
- this.resizeto.resizeNeeded();
- if (header.cc) {
- $('cc').setValue(header.cc);
- this.resizecc.resizeNeeded();
- }
- if (DIMP.conf_compose.cc) {
- this.toggleCC('cc');
- }
- if (header.bcc) {
- $('bcc').setValue(header.bcc);
- this.resizebcc.resizeNeeded();
- }
- if (identity.id[6]) {
- bcc_add = $F('bcc');
- if (bcc_add) {
- bcc_add += ', ';
- }
- $('bcc').setValue(bcc_add + identity.id[6]);
- }
- if (DIMP.conf_compose.bcc) {
- this.toggleCC('bcc');
- }
- $('subject').setValue(header.subject);
-
- Field.focus(focus || 'to');
- this.resizeMsgArea();
-
- if (DIMP.conf_compose.show_editor) {
- if (!this.editor_on) {
- this.toggleHtmlEditor(noupdate || false);
- }
- if (focus == 'message') {
- this.focusEditor();
- }
- }
- },
-
- focusEditor: function()
- {
- try {
- FCKeditorAPI.GetInstance('message').Focus();
- } catch (e) {
- this.focusEditor.bind(this).defer();
- }
- },
-
- addAttach: function(atc_num, name, type, size)
- {
- var span = new Element('SPAN').insert(name),
- div = new Element('DIV').insert(span).insert(' [' + type + '] (' + size + ' KB) '),
- input = new Element('SPAN', { atc_id: atc_num, className: 'remove' }).insert(DIMP.text_compose.remove);
- div.insert(input);
- $('attach_list').insert(div);
-
- if (type != 'application/octet-stream') {
- span.addClassName('attachName');
- }
-
- this.resizeMsgArea();
- },
-
- removeAttach: function(e)
- {
- var ids = [];
- e.each(function(n) {
- n = $(n);
- ids.push(n.down('SPAN.remove').readAttribute('atc_id'));
- n.remove();
- });
- DimpCore.doAction('DeleteAttach', { atc_indices: ids, imp_compose: $F('composeCache') });
- this.resizeMsgArea();
- },
-
- resizeMsgArea: function()
- {
- var m, rows,
- de = document.documentElement,
- msg = $('message');
-
- if (!document.loaded) {
- this.resizeMsgArea.bind(this).defer();
- return;
- }
-
- if (this.editor_on) {
- m = $('messageParent').select('iframe').last();
- if (m) {
- m.setStyle({ height: this.getMsgAreaHeight() + 'px' });
- } else {
- this.resizeMsgArea.bind(this).defer();
- }
- return;
- }
-
- this.mp_padding = $('messageParent').getHeight() - msg.getHeight();
-
- if (!this.row_height) {
- // Change the ID and name to not conflict with msg node.
- m = $(msg.cloneNode(false)).writeAttribute({ id: null, name: null }).setStyle({ visibility: 'hidden' });
- $(document.body).insert(m);
- m.writeAttribute('rows', 1);
- this.row_height = m.getHeight();
- m.writeAttribute('rows', 2);
- this.row_height = m.getHeight() - this.row_height;
- m.remove();
- }
-
- /* Logic: Determine the size of a given textarea row, divide that size
- * by the available height, round down to the lowest integer row, and
- * resize the textarea. */
- rows = parseInt(this.getMsgAreaHeight() / this.row_height);
- msg.writeAttribute({ rows: rows, disabled: false });
- if (de.scrollHeight - de.clientHeight) {
- msg.writeAttribute({ rows: rows - 1 });
- }
-
- $('composeloading').hide();
- },
-
- uploadAttachment: function()
- {
- var u = $('upload');
- this.uniqueSubmit('add_attachment');
- u.replace(new Element('DIV', { id: 'upload_wait' }).insert(DIMP.text_compose.uploading + ' ' + $F(u)));
- },
-
- attachmentComplete: function()
- {
- var sf = $('submit_frame'),
- doc = sf.contentDocument || sf.contentWindow.document;
- DimpCore.doActionComplete({ responseJSON: doc.body.innerHTML.evalJSON(true) }, this.uniqueSubmitCallback.bind(this));
- },
-
- toggleCC: function(type)
- {
- $('send' + type).show();
- $('toggle' + type).up().hide();
- },
-
- /* Sets the cursor to the given position. */
- setCursorPosition: function(input)
- {
- var pos, range;
-
- switch (DIMP.conf_compose.compose_cursor) {
- case 'top':
- pos = 0;
- $('message').setValue('\n' + $F('message'));
- break;
-
- case 'bottom':
- pos = $F('message').length;
- break;
-
- case 'sig':
- pos = $F('message').replace(/\r\n/g, '\n').lastIndexOf(this.get_identity($F('last_identity')).sig) - 1;
- break;
-
- default:
- return;
- }
-
- if (input.setSelectionRange) {
- /* This works in Mozilla */
- Field.focus(input);
- input.setSelectionRange(pos, pos);
- } else if (input.createTextRange) {
- /* This works in IE */
- range = input.createTextRange();
- range.collapse(true);
- range.moveStart('character', pos);
- range.moveEnd('character', 0);
- Field.select(range);
- range.scrollIntoView(true);
- }
- },
-
- /* Open the addressbook window. */
- openAddressbook: function()
- {
- window.open(DIMP.conf_compose.URI_ABOOK, 'contacts', 'toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes,width=550,height=300,left=100,top=100');
- },
-
- /* Click observe handler. */
- clickHandler: function(parentfunc, e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = orig = e.element(),
- atc_num, id;
-
- while (Object.isElement(elt)) {
- id = elt.readAttribute('id');
-
- switch (id) {
- case 'togglebcc':
- case 'togglecc':
- this.toggleCC(id.substring(6));
- this.resizeMsgArea();
- break;
-
- case 'compose_close':
- this.confirmCancel();
- break;
-
- case 'draft_button':
- case 'send_button':
- this.uniqueSubmit(id == 'send_button' ? 'send_message' : 'save_draft');
- break;
-
- case 'htmlcheckbox':
- this.toggleHtmlCheckbox();
- break;
-
- case 'sendcc':
- case 'sendbcc':
- case 'sendto':
- if (orig.match('TD.label SPAN')) {
- this.openAddressbook();
- }
- break;
-
- case 'attach_list':
- if (orig.match('SPAN.remove')) {
- this.removeAttach([ orig.up() ]);
- } else if (orig.match('SPAN.attachName')) {
- atc_num = orig.next().readAttribute('atc_id');
- DimpCore.popupWindow(DimpCore.addURLParam(DIMP.conf.URI_VIEW, { composeCache: $F('composeCache'), actionID: 'compose_attach_preview', id: atc_num }), $F('composeCache') + '|' + atc_num);
- }
- break;
- }
-
- elt = elt.up();
- }
-
- parentfunc(e);
- },
-
- changeHandler: function(e)
- {
- var elt = e.element(),
- id = elt.readAttribute('id');
-
- switch (id) {
- case 'identity':
- this.change_identity();
- break;
-
- case 'upload':
- this.uploadAttachment();
- break;
- }
- },
-
- onDomLoad: function()
- {
- var boundResize = this.resizeMsgArea.bind(this);
-
- DimpCore.growler_log = false;
- DimpCore.init();
-
- /* Attach event handlers. */
- document.observe('change', this.changeHandler.bindAsEventListener(this));
- Event.observe(window, 'resize', this.resizeMsgArea.bind(this));
- $('compose').observe('submit', Event.stop);
- $('submit_frame').observe('load', this.attachmentComplete.bind(this));
-
- this.resizeMsgArea();
- this.initializeSpellChecker();
-
- // Automatically resize address fields.
- this.resizeto = new ResizeTextArea('to', boundResize);
- this.resizecc = new ResizeTextArea('cc', boundResize);
- this.resizebcc = new ResizeTextArea('bcc', boundResize);
-
- // Safari requires a submit target iframe to be at least 1x1 size or
- // else it will open content in a new window. See:
- // http://blog.caboo.se/articles/2007/4/2/ajax-file-upload
- if (Prototype.Browser.WebKit) {
- $('submit_frame').writeAttribute({ position: 'absolute', width: '1px', height: '1px' }).setStyle({ left: '-999px' }).show();
- }
-
- /* Add addressbook link formatting. */
- if (DIMP.conf_compose.URI_ABOOK) {
- $('sendto', 'sendcc', 'sendbcc').each(function(a) {
- a.down('TD.label SPAN').addClassName('composeAddrbook');
- });
- }
- }
-
-},
-
-ResizeTextArea = Class.create({
- // Variables defaulting to empty:
- // defaultRows, field, onResize
- maxRows: 5,
-
- initialize: function(field, onResize)
- {
- this.field = $(field);
-
- this.defaultRows = Math.max(this.field.readAttribute('rows'), 1);
- this.onResize = onResize;
-
- var func = this.resizeNeeded.bindAsEventListener(this);
- this.field.observe('mousedown', func).observe('keyup', func);
-
- this.resizeNeeded();
- },
-
- resizeNeeded: function()
- {
- var lines = $F(this.field).split('\n'),
- cols = this.field.readAttribute('cols'),
- newRows = lines.size(),
- oldRows = this.field.readAttribute('rows');
-
- lines.each(function(line) {
- if (line.length >= cols) {
- newRows += Math.floor(line.length / cols);
- }
- });
-
- if (newRows != oldRows) {
- this.field.writeAttribute('rows', (newRows > oldRows) ? Math.min(newRows, this.maxRows) : Math.max(this.defaultRows, newRows));
-
- if (this.onResize) {
- this.onResize();
- }
- }
- }
-
-});
-
-/* Attach event handlers. */
-document.observe('dom:loaded', DimpCompose.onDomLoad.bind(DimpCompose));
-
-/* Click handler. */
-DimpCore.clickHandler = DimpCore.clickHandler.wrap(DimpCompose.clickHandler.bind(DimpCompose));
+++ /dev/null
-/**
- * Provides the javascript for the compose.php script (standard view).
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var ImpCompose = {
- /* Variables defined in compose.php:
- * cancel_url, spellcheck, cursor_pos, identities, max_attachments,
- * popup, redirect, reloaded, rtemode, smf_check, skip_spellcheck */
- display_unload_warning: true,
- textarea_ready: true,
-
- confirmCancel: function(e)
- {
- if (window.confirm(IMP.text.compose_cancel)) {
- this.display_unload_warning = false;
- if (this.popup) {
- if (this.cancel_url) {
- self.location = this.cancel_url;
- } else {
- self.close();
- }
- } else {
- window.location = this.cancel_url;
- }
- } else {
- e.stop();
- }
- },
-
- /**
- * Sets the cursor to the given position.
- */
- setCursorPosition: function(input, position)
- {
- if (input.setSelectionRange) {
- /* This works in Mozilla */
- Field.focus(input);
- input.setSelectionRange(position, position);
- } else if (input.createTextRange) {
- /* This works in IE */
- var range = input.createTextRange();
- range.collapse(true);
- range.moveStart('character', position);
- range.moveEnd('character', 0);
- Field.select(range);
- range.scrollIntoView(true);
- }
- },
-
- changeIdentity: function(elt)
- {
- var id = $F(elt),
- last = this.identities[$F('last_identity')],
- next = this.identities[id],
- i = 0,
- bcc = $('bcc'),
- save = $('ssm'),
- smf = $('sent_mail_folder'),
- ed, lastSignature, msg, nextSignature, pos, re;
-
- // If the rich text editor is on, we'll use a regexp to find the
- // signature comment and replace its contents.
- if (this.rtemode) {
- ed = FCKeditorAPI.GetInstance('message');
-
- msg = ed.GetHTML.replace(/\r\n/g, '\n');
-
- lastSignature = '<p><!--begin_signature--><!--end_signature--></p>';
- nextSignature = '<p><!--begin_signature-->' + next[0].replace(/^ ?<br \/>\n/, '').replace(/ +/g, ' ') + '<!--end_signature--></p>';
-
- // Dot-all functionality achieved with [\s\S], see:
- // http://simonwillison.net/2004/Sep/20/newlines/
- msg = msg.replace(/<p class="imp-signature">\s*<!--begin_signature-->[\s\S]*?<!--end_signature-->\s*<\/p>/, lastSignature);
- } else {
- msg = $F('message').replace(/\r\n/g, '\n');
-
- lastSignature = last[0].replace(/^\n/, '');
- nextSignature = next[0].replace(/^\n/, '');
- }
-
- pos = (last[1]) ? msg.indexOf(lastSignature) : msg.lastIndexOf(lastSignature);
- if (pos != -1) {
- if (next[1] == last[1]) {
- msg = msg.substring(0, pos) + nextSignature + msg.substring(pos + lastSignature.length, msg.length);
- } else if (next[1]) {
- msg = nextSignature + msg.substring(0, pos) + msg.substring(pos + lastSignature.length, msg.length);
- } else {
- msg = msg.substring(0, pos) + msg.substring(pos + lastSignature.length, msg.length) + nextSignature;
- }
-
- msg = msg.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');
-
- $('last_identity').setValue(id);
- window.status = IMP.text.compose_sigreplace;
- } else {
- window.status = IMP.text.compose_signotreplace;
- }
-
- if (this.rtemode) {
- ed.SetHTML(msg);
- } else {
- $('message').setValue(msg);
- }
-
-
- if (this.smf_check) {
- $A(smf.options).detect(function(f) {
- if (f.value == next[2]) {
- smf.selectedIndex = i;
- return true;
- }
- ++i;
- });
- } else {
- if (smf.firstChild) {
- smf.replaceChild(document.createTextNode(next[2]), smf.firstChild);
- } else {
- smf.appendChild(document.createTextNode(next[2]));
- }
- }
-
- if (save) {
- save.checked = next[3];
- }
- if (bcc) {
- bccval = bcc.value;
-
- if (last[4]) {
- re = new RegExp(last[4] + ",? ?", 'gi');
- bccval = bccval.replace(re, "");
- if (bccval) {
- bccval = bccval.replace(/, ?$/, "");
- }
- }
-
- if (next[4]) {
- if (bccval) {
- bccval += ', ';
- }
- bccval += next[4];
- }
-
- bcc.setValue(bccval);
- }
- },
-
- uniqSubmit: function(actionID, e)
- {
- var form;
-
- if (!Object.isUndefined(e)) {
- e.stop();
- }
-
- switch (actionID) {
- case 'redirect':
- if ($F('to') == '') {
- alert(IMP.text.compose_recipient);
- $('to').focus();
- return;
- }
-
- form = $('redirect');
- break;
-
- case 'send_message':
- if (($F('subject') == '') &&
- !window.confirm(IMP.text.compose_nosubject)) {
- return;
- }
-
- if (!this.skip_spellcheck &&
- this.spellcheck &&
- IMP.SpellCheckerObject &&
- !IMP.SpellCheckerObject.isActive()) {
- IMP.SpellCheckerObject.spellCheck(this.onNoSpellError.bind(this, actionID, e));
- return;
- }
-
- this.skip_spellcheck = false;
-
- if (IMP.SpellCheckerObject) {
- IMP.SpellCheckerObject.resume();
- }
-
- // fall through
-
- case 'add_attachment':
- case 'save_draft':
- form = $('compose');
- $('actionID').setValue(actionID);
- break;
-
- case 'toggle_editor':
- form = $('compose');
- break;
-
- default:
- return;
- }
-
- // Ticket #6727; this breaks on WebKit w/FCKeditor.
- if (!Prototype.Browser.WebKit) {
- form.setStyle({ cursor: 'wait' });
- }
-
- this.display_unload_warning = false;
- this._uniqSubmit(form);
- },
-
- _uniqSubmit: function(form)
- {
- if (this.textarea_ready) {
- form.submit();
- } else {
- this._uniqSubmit.bind(this, form).defer();
- }
- },
-
- onNoSpellError: function(actionID, e)
- {
- this.skip_spellcheck = true;
- this.uniqSubmit(actionID, e);
- },
-
- attachmentChanged: function()
- {
- var fields = [],
- usedFields = 0,
- lastRow, newRow, td;
-
- $('upload_atc').select('input[type="file"]').each(function(i) {
- fields[fields.length] = i;
- });
-
- if (this.max_attachments !== null &&
- fields.length == this.max_attachments) {
- return;
- }
-
- fields.each(function(i) {
- if (i.value.length > 0) {
- usedFields++;
- }
- });
-
- if (usedFields == fields.length) {
- lastRow = $('attachment_row_' + usedFields);
- if (lastRow) {
- td = new Element('TD', { align: 'left' }).insert(new Element('STRONG').insert(IMP.text.compose_file + ' ' + (usedFields + 1) + ':')).insert(' ')
-
- td.insert(new Element('INPUT', { type: 'file', id: 'upload_' + (usedFields + 1), name: 'upload_' + (usedFields + 1), size: 25 }));
-
- newRow = new Element('TR', { id: 'attachment_row_' + (usedFields + 1) }).insert(td);
-
- lastRow.parentNode.insertBefore(newRow, lastRow.nextSibling);
- }
- }
- },
-
- initializeSpellChecker: function()
- {
- if (typeof IMP.SpellCheckerObject != 'object') {
- // If we fired before the onload that initializes the spellcheck,
- // wait.
- this.initializeSpellChecker.bind(this).defer();
- return;
- }
-
- IMP.SpellCheckerObject.onBeforeSpellCheck = this._beforeSpellCheck.bind(this);
- IMP.SpellCheckerObject.onAfterSpellCheck = this._afterSpellCheck.bind(this);
- },
-
- _beforeSpellCheck: function()
- {
- IMP.SpellCheckerObject.htmlAreaParent = 'messageParent';
- IMP.SpellCheckerObject.htmlArea = $('message').adjacent('iframe[id*=message]').first();
- $('message').setValue(FCKeditorAPI.GetInstance('message').GetHTML());
- this.textarea_ready = false;
- },
-
- _afterSpellCheck: function()
- {
- IMP.SpellCheckerObject.htmlArea = IMP.SpellCheckerObject.htmlAreaParent = null;
- var ed = FCKeditorAPI.GetInstance('message');
- ed.SetHTML($('message').value);
- ed.Events.AttachEvent('OnAfterSetHTML', this._afterSetHTML.bind(this));
- },
-
- _afterSetHTML: function()
- {
- this.textarea_ready = true;
- },
-
- clickHandler: function(e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = e.element(), name;
-
- while (Object.isElement(elt)) {
- if (elt.hasClassName('button')) {
- name = elt.readAttribute('name');
- switch (name) {
- case 'btn_add_attachment':
- case 'btn_redirect':
- case 'btn_save_draft':
- case 'btn_send_message':
- this.uniqSubmit(name.substring(4), e);
- break;
-
- case 'btn_cancel_compose':
- this.confirmCancel(e);
- break;
- }
- }
-
- elt = elt.up();
- }
- },
-
- changeHandler: function(e)
- {
- var elt = e.element(),
- id = elt.identify();
-
- switch (id) {
- case 'identity':
- this.changeIdentity(elt);
- break;
-
- case 'stationery':
- this.uniqSubmit('change_stationery', e);
- break;
-
- case 'sent_mail_folder':
- $('ssm').writeAttribute('checked', 'checked');
- break;
-
- default:
- if (id.substring(0, 7) == 'upload_') {
- this.attachmentChanged();
- }
- break;
- }
- },
-
- onDomLoad: function()
- {
- /* Prevent Return from sending messages - it should bring us out of
- * autocomplete, not submit the whole form. */
- $$('INPUT').each(function(i) {
- /* Attach to everything but button and submit elements. */
- if (i.type != 'submit' && i.type != 'button') {
- i.observe('keydown', function(e) {
- if (e.keyCode == 10 || e.keyCode == Event.KEY_RETURN) {
- e.stop();
- return false;
- }
- });
- }
- });
-
- if (this.cursor_pos !== null && $('message')) {
- this.setCursorPosition($('message'), this.cursor_pos);
- }
-
- if (this.redirect) {
- $('to').focus();
- } else {
- if (Prototype.Browser.IE) {
- $('subject').observe('keydown', function(e) {
- if (e.keyCode == Event.KEY_TAB && !e.shiftKey) {
- e.stop();
- $('message').focus();
- }
- });
- }
-
- if (this.rtemode) {
- this.initializeSpellChecker();
- }
-
- if ($('to') && !$F('to')) {
- $('to').focus();
- } else if (!$F('subject')) {
- if (this.rtemode) {
- $('subject').focus();
- } else {
- $('message').focus();
- }
- }
- }
- },
-
- onLoad: function()
- {
- var d, e = this.redirect ? $('redirect') : $('compose');
-
- if (this.popup && !this.reloaded) {
- d = Math.min(e.getHeight(), screen.height - 100) - document.viewport.getHeight();
- if (d > 0) {
- window.resizeBy(0, d);
- }
- }
-
- document.observe('click', this.clickHandler.bindAsEventListener(this));
- document.observe('change', this.changeHandler.bindAsEventListener(this));
- },
-
- onBeforeUnload: function()
- {
- if (this.display_unload_warning) {
- return IMP.text.compose_discard;
- }
- }
-
-};
-
-/* Code to run on window load. */
-document.observe('dom:loaded', ImpCompose.onDomLoad.bind(ImpCompose));
-Event.observe(window, 'load', ImpCompose.onLoad.bind(ImpCompose));
-
-/* Warn before closing the window. */
-Event.observe(window, 'beforeunload', ImpCompose.onBeforeUnload.bind(ImpCompose));
+++ /dev/null
-/**
- * Provides the javascript for the contacts.php script (standard view).
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var ImpContacts = {
- // The following variables are defined in contacts.php:
- // formname, to_only
-
- _passAddresses: function()
- {
- var sa = '';
-
- $('selected_addresses').childElements().each(function(s) {
- if (s.value) {
- sa += s.value + '|';
- }
- });
-
- $('sa').setValue(sa);
- },
-
- sameOption: function(f, item, itemj)
- {
- var t = f + ": " + item.value,
- tj = itemj.value;
-
- return Try.these(
- function() {
- return (t == tj) || (decodeURIComponent(t) == decodeURIComponent(tj));
- },
- // Catch exception with NS 7.1
- function() {
- return (t == tj);
- }
- );
- },
-
- addAddress: function(f)
- {
- var d, l, option, s = $('search_results');
-
- if (!$F(s).size()) {
- alert(IMP.text.contacts_select);
- } else {
- d = $('selected_addresses');
- l = $A(d).size();
- s.childElements().each(function(i) {
- if (i.value && i.selected) {
- if (!$A(d).any(function(j) {
- return this.sameOption(f, i, j);
- }, this)) {
- option = f + ': ' + i.value;
- d[l++] = new Option(option, option);
- }
- }
- }, this);
- }
- },
-
- updateMessage: function()
- {
- if (parent.opener.closed) {
- alert(IMP.text.contacts_closed);
- window.close();
- return;
- }
-
- if (!parent.opener.document[this.formname]) {
- alert(IMP.text.contacts_called);
- window.close();
- return;
- }
-
- $('selected_addresses').childElements().each(function(s) {
- var address = s.value, f, field = null, pos, v;
- pos = address.indexOf(':');
- f = address.substring(0, pos);
- address = address.substring(pos + 2, address.length)
-
- if (f == 'to') {
- field = parent.opener.document[this.formname].to;
- } else if (!this.to_only && f == 'cc') {
- field = parent.opener.document[this.formname].cc;
- } else if (!this.to_only && f == 'bcc') {
- field = parent.opener.document[this.formname].bcc;
- }
-
- if (!field) {
- return;
- }
-
- // Always delimit with commas.
- if (field.value.length) {
- v = field.value.replace(/, +/g, ',').split(',').findAll(function(s) { return s; });
- field.value = v.join(', ');
- if (field.value.lastIndexOf(';') != field.value.length - 1) {
- field.value += ',';
- }
- field.value += ' ' + address;
- } else {
- field.value = address;
- }
- if (address.lastIndexOf(';') != address.length - 1) {
- field.value += ', ';
- }
- }, this);
-
- window.close();
- },
-
- removeAddress: function()
- {
- $('selected_addresses').childElements().each(function(o) {
- if (o.selected) {
- o.remove();
- }
- });
- },
-
- onDomLoad: function()
- {
- $('contacts').observe('submit', this._passAddresses.bind(this));
- document.observe('change', this._changeHandler.bindAsEventListener(this));
- document.observe('click', this._clickHandler.bindAsEventListener(this));
- document.observe('dblclick', this._dblclickHandler.bindAsEventListener(this));
- },
-
- _changeHandler: function(e)
- {
- var id = e.element().readAttribute('id');
-
- switch (id) {
- case 'search_results':
- $(id)[0].selected = false;
- break;
- }
- },
-
- _clickHandler: function(e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = e.element(), id;
-
- while (Object.isElement(elt)) {
- id = elt.readAttribute('id');
-
- switch (id) {
- case 'btn_add_to':
- case 'btn_add_cc':
- case 'btn_add_bcc':
- this.addAddress(id.substring(8));
- break;
-
- case 'btn_update':
- this.updateMessage();
- break;
-
- case 'btn_delete':
- this.removeAddress();
- break;
-
- case 'btn_cancel':
- window.close();
- break;
- }
-
- elt = elt.up();
- }
- },
-
- _dblclickHandler: function(e)
- {
- var elt = e.element();
- if (!elt.match('SELECT')) {
- elt = elt.up('SELECT');
- }
-
- switch (elt.readAttribute('id')) {
- case 'search_results':
- this.addAddress('to');
- break;
-
- case 'selected_addresses':
- this.removeAddress();
- break;
- }
- }
-
-};
-
-document.observe('dom:loaded', ImpContacts.onDomLoad.bind(ImpContacts));
+++ /dev/null
-/**
- * Javascript code used to display a RedBox dialog.
- *
- * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@curecanti.org>
- */
-
-var IMPDialog = {
-
- display: function(data)
- {
- if (Object.isString(data)) {
- data = decodeURIComponent(data).evalJSON(true);
- }
- if (data.dialog_load) {
- new Ajax.Request(data.dialog_load, { onComplete: this._onComplete.bind(this) });
- } else {
- this._display(data);
- }
- },
-
- _onComplete: function(response)
- {
- this._display(response.responseJSON.response);
- },
-
- _display: function(data)
- {
- this.action = data.action;
- this.params = data.params;
- this.uri = data.uri;
-
- var n = new Element('FORM', { action: '#', id: 'RB_confirm' }).insert(
- new Element('P').insert(data.text)
- );
-
- if (data.form) {
- n.insert(data.form);
- } else {
- n.insert(new Element('INPUT', { name: 'dialog_input', type: data.password ? 'password' : 'text', size: 15 }));
- }
-
- if (data.ok_text) {
- n.insert(
- new Element('INPUT', { type: 'button', className: 'button', value: data.ok_text }).observe('click', this._onClick.bind(this))
- );
- }
-
- n.insert(
- new Element('INPUT', { type: 'button', className: 'button', value: data.cancel_text }).observe('click', this._close.bind(this))
- ).observe('keydown', function(e) { if ((e.keyCode || e.charCode) == Event.KEY_RETURN) { e.stop(); this._onClick(e); } }.bind(this));
-
- RedBox.overlay = true;
- RedBox.onDisplay = Form.focusFirstElement.curry(n);
- RedBox.showHtml(n);
- },
-
- _close: function()
- {
- var c = RedBox.getWindowContents();
- [ c, c.descendants()].flatten().compact().invoke('stopObserving');
- RedBox.close();
- },
-
- _onClick: function(e)
- {
- var params = $H((!this.params || Object.isArray(this.params)) ? {} : this.params);
- params.update(e.findElement('form').serialize(true));
-
- new Ajax.Request(this.uri, { parameters: params, onSuccess: this._onSuccess.bind(this), onFailure: this._onFailure.bind(this) });
- },
-
- _onSuccess: function(r)
- {
- r = r.responseJSON;
-
- if (r.response.success) {
- this._close();
- if (this.action) {
- if (Object.isFunction(this.action)) {
- this.action();
- } else {
- eval(this.action)();
- }
- } else {
- location.reload();
- }
- } else if (r.response.error) {
- alert(r.response.error);
- }
- },
-
- _onFailure: function(r)
- {
- }
-
-};
+++ /dev/null
-/**
- * Provides the javascript for the fetchmailprefs.php script.
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var ImpFetchmailprefs = {
-
- // The following variables are defined in fetchmailprefs.php:
- // fetchurl, prefsurl
- fmprefs_loading: false,
-
- _accountSubmit: function(isnew)
- {
- if (!this.fmprefs_loading &&
- ((isnew != null) || !$F('account').empty())) {
- this.fmprefs_loading = true;
- $('fm_switch').submit();
- }
- },
-
- _driverSubmit: function()
- {
- if (!this.fmprefs_loading && $F('fm_driver')) {
- this.fmprefs_loading = true;
- $('fm_driver_form').submit();
- }
- },
-
- onDomLoad: function()
- {
- document.observe('change', this._changeHandler.bindAsEventListener(this));
- document.observe('click', this._clickHandler.bindAsEventListener(this));
- },
-
- _changeHandler: function(e)
- {
- switch (e.element().readAttribute('id')) {
- case 'account':
- this._accountSubmit();
- break;
-
- case 'fm_driver':
- this._driverSubmit();
- break;
- }
- },
-
- _clickHandler: function(e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = e.element();
-
- while (Object.isElement(elt)) {
- switch (elt.readAttribute('id')) {
- case 'btn_delete':
- $('actionID').setValue('fetchmail_prefs_delete');
- break;
-
- case 'btn_create':
- $('actionID').setValue('fetchmail_create');
- this._accountSubmit(true);
- break;
-
- case 'btn_return':
- document.location.href = this.prefsurl;
- break;
-
- case 'btn_save':
- $('actionID').setValue('fetchmail_prefs_save');
- break;
-
- case 'btn_select':
- document.location.href = this.fetchurl;
- break;
- }
-
- elt = elt.up();
- }
- }
-
-};
-
-document.observe('dom:loaded', ImpFetchmailprefs.onDomLoad.bind(ImpFetchmailprefs));
+++ /dev/null
-/**
- * Provides the javascript for managing message flags.
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var ImpFlagmanagement = {
- // Variables set by other code: confirm_delete, new_prompt
-
- addFlag: function()
- {
- var category = window.prompt(this.new_prompt, '');
- if (category) {
- this._sendData('add', category);
- }
- },
-
- _sendData: function(a, d)
- {
- $('flag_action').setValue(a)
- $('flag_data').setValue(d);
- $('prefs').submit();
- },
-
- clickHandler: function(e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = e.element(), elt2, id;
-
- while (Object.isElement(elt)) {
- if (elt.hasClassName('flagcolorpicker')) {
- elt2 = elt.previous('INPUT');
- id = elt2.readAttribute('id');
- new ColorPicker({
- color: $F(elt2),
- offsetParent: elt,
- update: [[ id, 'value' ], [ id, 'background' ]]
- });
- e.stop();
- return;
- }
-
- if (elt.hasClassName('flagdelete')) {
- if (window.confirm(this.confirm_delete)) {
- this._sendData('delete', elt.previous('INPUT').readAttribute('id'));
- }
- e.stop();
- return;
- }
-
- switch (elt.readAttribute('id')) {
- case 'new_button':
- this.addFlag();
- break;
- }
-
- elt = elt.up();
- }
- },
-
- resetHandler: function()
- {
- $('prefs').getInputs('text').each(function(i) {
- if (i.readAttribute('id').startsWith('color_')) {
- i.setStyle({ backgroundColor: $F(i) });
- }
- });
- }
-
-};
-
-document.observe('dom:loaded', function() {
- var fm = ImpFlagmanagement;
- document.observe('click', fm.clickHandler.bindAsEventListener(fm));
- $('prefs').observe('reset', function() { fm.resetHandler.defer(); });
-});
+++ /dev/null
-/**
- * Provides the javascript for the compose.php script (standard view).
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var ImpFolders = {
-
- // The following variables are defined in folders.php:
- // displayNames, folders_url
-
- getChecked: function()
- {
- return this.getFolders().findAll(function(e) {
- return e.checked;
- });
- },
-
- getFolders: function()
- {
- return $('fmanager').getInputs(null, 'folder_list[]');
- },
-
- selectedFoldersDisplay: function()
- {
- var folder = 0, sel = "";
-
- this.getFolders().each(function(e) {
- if (e.checked) {
- sel += this.displayNames[folder] + "\n";
- }
- ++folder;
- }, this);
-
- return sel.strip();
- },
-
- chooseAction: function(e)
- {
- var id = (e.element().readAttribute('id') == 'action_choose0') ? 0 : 1,
- a = $('action_choose' + id),
- action = $F(a);
- a.selectedIndex = 0;
-
- switch (action) {
- case 'create_folder':
- this.createMailbox();
- break;
-
- case 'rebuild_tree':
- this.submitAction(action);
- break;
-
- default:
- if (!this.getChecked().size()) {
- if (action != '') {
- alert(IMP.text.folders_select);
- }
- break;
- }
-
- switch (action) {
- case 'rename_folder':
- this.renameMailbox();
- break;
-
- case 'subscribe_folder':
- case 'unsubscribe_folder':
- case 'poll_folder':
- case 'expunge_folder':
- case 'nopoll_folder':
- case 'mark_folder_seen':
- case 'mark_folder_unseen':
- case 'delete_folder_confirm':
- case 'folders_empty_mailbox_confirm':
- case 'mbox_size':
- this.submitAction(action);
- break;
-
- case 'download_folder':
- case 'download_folder_zip':
- this.downloadMailbox(action);
- break;
-
- case 'import_mbox':
- if (this.getChecked().length > 1) {
- alert(IMP.text.folders_oneselect);
- } else {
- this.submitAction(action);
- }
- break;
- }
-
- break;
- }
- },
-
- submitAction: function(a)
- {
- $('actionID').setValue(a);
- $('fmanager').submit();
- },
-
- createMailbox: function()
- {
- var count = this.getChecked().size(), mbox;
- if (count > 1) {
- window.alert(IMP.text.folders_oneselect);
- return;
- }
-
- mbox = (count == 1)
- ? window.prompt(IMP.text.folders_subfolder1 + ' ' + this.selectedFoldersDisplay() + ".\n" + IMP.text.folders_subfolder2 + "\n", '')
- : window.prompt(IMP.text.folders_toplevel, '');
-
- if (mbox) {
- $('new_mailbox').setValue(mbox);
- this.submitAction('create_folder');
- }
- },
-
- downloadMailbox: function(actionid)
- {
- if (window.confirm(IMP.text.folders_download1 + "\n" + this.selectedFoldersDisplay() + "\n" + IMP.text.folders_download2)) {
- this.submitAction(actionid);
- }
- },
-
- renameMailbox: function()
- {
- var newnames = '', oldnames = '', j = 0;
-
- this.getFolders().each(function(f) {
- if (f.checked) {
- if (IMP.conf.fixed_folders.indexOf(this.displayNames[j]) != -1) {
- window.alert(IMP.text.folders_no_rename + ' ' + this.displayNames[j]);
- } else {
- var tmp = window.prompt(IMP.text.folders_rename1 + ' ' + this.displayNames[j] + "\n" + IMP.text.folders_rename2, this.displayNames[j]);
- if (tmp) {
- newnames += tmp + "\n";
- oldnames += f.value + "\n";
- }
- }
- }
- ++j;
- }, this);
-
- if (newnames) {
- $('new_names').setValue(newnames.strip());
- $('old_names').setValue(oldnames.strip());
- this.submitAction('rename_folder');
- }
- },
-
- toggleSelection: function()
- {
- var count = this.getChecked().size(), folders = this.getFolders(),
- checked = (count != folders.size());
- folders.each(function(f) {
- f.checked = checked;
- });
- },
-
- changeHandler: function(e)
- {
- switch (e.element().readAttribute('id')) {
- case 'action_choose0':
- case 'action_choose1':
- this.chooseAction(e);
- break;
- }
- },
-
- clickHandler: function(e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = e.element();
-
- while (Object.isElement(elt)) {
- switch (elt.readAttribute('id')) {
- case 'btn_import':
- this.submitAction('import_mbox');
- break;
-
- case 'btn_return':
- document.location.href = this.folders_url;
- break;
-
- case 'checkAll0':
- case 'checkAll1':
- this.toggleSelection();
- break;
- }
-
- elt = elt.up();
- }
- }
-
-};
-
-document.observe('change', ImpFolders.changeHandler.bind(ImpFolders));
-document.observe('click', ImpFolders.clickHandler.bind(ImpFolders));
+++ /dev/null
-/**
- * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var DimpFullmessage = {
-
- // Variables defaulting to empty/false:
- // index, mailbox
- quickreply: function(type)
- {
- var func, ob = {};
- ob[this.mailbox] = [ this.index ];
-
- $('msgData').hide();
- $('qreply').show();
-
- switch (type) {
- case 'reply':
- case 'reply_all':
- case 'reply_list':
- func = 'GetReplyData';
- break;
-
- case 'forward':
- func = 'GetForwardData';
- break;
- }
-
- DimpCore.doAction(func,
- { imp_compose: $F('composeCache'),
- type: type },
- ob,
- this.msgTextCallback.bind(this));
- },
-
- msgTextCallback: function(result)
- {
- if (!result.response) {
- return;
- }
-
- var r = result.response,
- editor_on = ((r.format == 'html') && !DimpCompose.editor_on),
- id = (r.identity === null) ? $F('identity') : r.identity,
- i = DimpCompose.get_identity(id, editor_on);
-
- $('identity', 'last_identity').invoke('setValue', id);
-
- DimpCompose.fillForm((i.id[2]) ? ("\n" + i.sig + r.body) : (r.body + "\n" + i.sig), r.header);
-
- if (r.fwd_list && r.fwd_list.length) {
- r.fwd_list.each(function(ptr) {
- DimpCompose.addAttach(ptr.number, ptr.name, ptr.type, ptr.size);
- });
- }
-
- if (editor_on) {
- DimpCompose.toggleHtmlEditor(true);
- }
-
- if (r.imp_compose) {
- $('composeCache').setValue(r.imp_compose);
- }
- },
-
- /* Click handlers. */
- clickHandler: function(parentfunc, e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = orig = e.element(), id;
-
- while (Object.isElement(elt)) {
- id = elt.readAttribute('id');
-
- switch (id) {
- case 'windowclose':
- window.close();
- e.stop();
- return;
-
- case 'forward_link':
- case 'reply_link':
- this.quickreply(id == 'reply_link' ? 'reply' : 'forward');
- e.stop();
- return;
-
- case 'button_deleted':
- case 'button_ham':
- case 'button_spam':
- if (id == 'button_deleted') {
- DIMP.baseWindow.DimpBase.deleteMsg({ index: this.index, mailbox: this.mailbox });
- } else {
- DIMP.baseWindow.DimpBase.reportSpam(id == 'button_spam', { index: this.index, mailbox: this.mailbox });
- }
- window.close();
- e.stop();
- return;
-
- case 'msgloglist_toggle':
- case 'partlist_toggle':
- tmp = (id == 'partlist_toggle') ? 'partlist' : 'msgloglist';
- $(tmp + '_col', tmp + '_exp').invoke('toggle');
- Effect.toggle(tmp, 'blind', {
- afterFinish: function() {
- this.resizeWindow();
- $('msgData').down('DIV.msgBody').setStyle({ overflowY: 'auto' })
- }.bind(this),
- beforeSetup: function() {
- $('msgData').down('DIV.msgBody').setStyle({ overflowY: 'hidden' })
- },
- duration: 0.2,
- queue: {
- position: 'end',
- scope: tmp,
- limit: 2
- }
- });
- break;
-
- case 'msg_view_source':
- DimpCore.popupWindow(DimpCore.addURLParam(DIMP.conf.URI_VIEW, { uid: this.index, mailbox: this.mailbox, actionID: 'view_source', id: 0 }, true), DIMP.conf.msg_index + '|' + DIMP.conf.msg_folder);
- break;
-
- case 'qreply':
- if (orig.match('DIV.headercloseimg IMG')) {
- DimpCompose.confirmCancel();
- }
- break;
- }
-
- elt = elt.up();
- }
-
- parentfunc(e);
- },
-
- contextOnClick: function(parentfunc, elt, baseelt, menu)
- {
- var id = elt.readAttribute('id');
-
- switch (id) {
- case 'ctx_reply_reply':
- case 'ctx_reply_reply_all':
- case 'ctx_reply_reply_list':
- this.quickreply(id.substring(10));
- break;
-
- default:
- parentfunc(elt, baseelt, menu);
- break;
- }
- },
-
- /* Add a popdown menu to a dimpactions button. */
- addPopdown: function(bid, ctx)
- {
- var bidelt = $(bid);
- bidelt.insert({ after: new Element('SPAN', { className: 'iconImg popdownImg popdown', id: bid + '_img' }) });
- DimpCore.DMenu.addElement(bid + '_img', 'ctx_' + ctx, { offset: bidelt.up(), left: true });
- },
-
- resizeWindow: function()
- {
- var mb = $('msgData').down('DIV.msgBody');
-
- mb.setStyle({ height: (document.viewport.getHeight() - mb.cumulativeOffset()[1] - parseInt(mb.getStyle('paddingTop'), 10) - parseInt(mb.getStyle('paddingBottom'), 10)) + 'px' });
- },
-
- onDomLoad: function()
- {
- DimpCore.growler_log = false;
- DimpCore.init();
-
- if (DIMP.conf.disable_compose) {
- tmp = $('reply_link', 'forward_link').compact().invoke('up', 'SPAN').concat([ $('ctx_contacts_new') ]).compact().invoke('remove');
- } else {
- this.addPopdown('reply_link', 'replypopdown');
- }
-
- /* Set up address linking. */
- [ 'from', 'to', 'cc', 'bcc', 'replyTo' ].each(function(a) {
- if (this[a]) {
- var elt = $('msgHeader' + a.charAt(0).toUpperCase() + a.substring(1)).down('TD', 1);
- elt.replace(DimpCore.buildAddressLinks(this[a], elt.cloneNode(false)));
- }
- }, this);
-
- /* Add message information. */
- if (this.log) {
- $('msgLogInfo').show();
- DimpCore.updateMsgLog(this.log);
- }
-
- this.resizeWindow();
- }
-
-};
-
-/* ContextSensitive functions. */
-DimpCore.contextOnClick = DimpCore.contextOnClick.wrap(DimpFullmessage.contextOnClick.bind(DimpFullmessage));
-
-/* Click handler. */
-DimpCore.clickHandler = DimpCore.clickHandler.wrap(DimpFullmessage.clickHandler.bind(DimpFullmessage));
-
-/* Attach event handlers. */
-document.observe('dom:loaded', DimpFullmessage.onDomLoad.bind(DimpFullmessage));
-Event.observe(window, 'resize', DimpFullmessage.resizeWindow.bind(DimpFullmessage));
+++ /dev/null
-/**
- * Provides basic IMP javascript functions.
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-document.observe('dom:loaded', function() {
- if (!window.IMP) {
- window.IMP = {};
- }
-
- window.IMP.menuFolderSubmit = function(clear)
- {
- var mf = $('menuform');
-
- if ((!this.menufolder_load || clear) &&
- $F(mf.down('SELECT[name="mailbox"]'))) {
- this.menufolder_load = true;
- mf.submit();
- }
- };
-
- /**
- * Use DOM manipulation to un-block images.
- */
- window.IMP.unblockImages = function(e)
- {
- var elt = e.element().up('TABLE.mimeStatusMessage');
-
- elt.next('.htmlMessage').select('[blocked]').each(function(e) {
- var src = decodeURIComponent(e.readAttribute('blocked'));
- if (e.hasAttribute('src')) {
- e.writeAttribute('src', src);
- } else if (e.hasAttribute('background')) {
- e.writeAttribute('background', src);
- } else if (e.style.backgroundImage) {
- e.setStyle({ backgroundImage: 'url(' + src + ')' });
- }
- });
-
- Effect.Fade(elt, {
- afterFinish: function() { elt.remove(); },
- duration: 0.6
- });
-
- e.stop();
- };
-
- // If menu is present, attach event handlers to folder switcher.
- var tmp = $('openfoldericon');
- if (tmp) {
- $('menuform').observe('change', window.IMP.menuFolderSubmit.bind(window.IMP));
- tmp.down().observe('click', window.IMP.menuFolderSubmit.bind(window.IMP, true));
- }
-});
+++ /dev/null
-/**
- * Provides the javascript for the login.php script.
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var ImpLogin = {
- // The following variables are defined in login.php:
- // dimp_sel, server_key_error
-
- submit: function(parentfunc)
- {
- if ($('imp_server_key') && $F('imp_server_key').startsWith('_')) {
- alert(this.server_key_error);
- $('imp_server_key').focus();
- return;
- }
-
- parentfunc();
- },
-
- onDomLoad: function()
- {
- /* Activate dynamic view. */
- var o = $('imp_select_view').down('option[value=dimp]').show();
- if (this.dimp_sel) {
- o.writeAttribute('selected', 'selected');
- }
- }
-};
-
-HordeLogin.submit = HordeLogin.submit.wrap(ImpLogin.submit.bind(ImpLogin));
-document.observe('dom:loaded', ImpLogin.onDomLoad.bind(ImpLogin));
+++ /dev/null
-/**
- * mailbox-dimp.js - Template used to format the rows in the message list
- * display.
- *
- * 'vpData' is a mandatory entry for ID/class information automatically
- * generated by ViewPort.js.
- * 'status', 'style', and 'subjectdata' are entries that are internally
- * created by DimpBase.js.
- *
- * See the documentation of prototypejs - Template for the template format:
- * http://www.prototypejs.org/api/template
- *
- * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-DimpBase.message_list_template =
-'<div #{vpData} style="#{style}">' +
- '<div class="msgStatus">' +
- '<div class="msCheck"></div>' +
- '#{status}' +
- '</div>' +
- '<div class="msgFrom">#{from}</div>' +
- '<div class="msgSubject" title="#{subjecttitle}">#{subjectdata}#{subject}</div>' +
- '<div class="msgDate">#{date}</div>' +
- '<div class="msgSize">#{size}</div>' +
-'</div>';
+++ /dev/null
-/**
- * Provides the javascript for the mailbox.php script (standard view).
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var ImpMailbox = {
- // The following variables are defined in mailbox.php:
- // sortlimit, unread
-
- anySelected: function()
- {
- return $('messages').select('[name="indices[]"]').detect(Form.Element.getValue);
- },
-
- selectRow: function(id, select)
- {
- [ id ].invoke(select ? 'addClassName' : 'removeClassName', 'selectedRow');
- id.down('INPUT.checkbox').setValue(select);
- },
-
- confirmDialog: function(url, msg)
- {
- RedBox.overlay = true;
- RedBox.showHtml('<div id="RB_confirm"><p>' + msg + '</p><input type="button" class="button" onclick="window.location=\'' + url + '\';" value="' + IMP.text.yes + '" />' +
- '<input type="button" class="button" onclick="RedBox.close();" value="' + IMP.text.no + '" /></div>');
- },
-
- submit: function(actID)
- {
- if (!this.anySelected()) {
- alert(IMP.text.mailbox_submit);
- return;
- }
-
- switch (actID) {
- case 'delete_messages':
- if (IMP.conf.pop3 && !confirm(IMP.text.mailbox_delete)) {
- return;
- }
- break;
-
- case 'spam_report':
- if (!confirm(IMP.text.spam_report)) {
- return;
- }
- break;
-
- case 'nostpam_report':
- if (!confirm(IMP.text.notspam_report)) {
- return;
- }
- break;
- }
-
- $('actionID').setValue(actID);
- $('messages').submit();
- },
-
- selectRange: function(e)
- {
- // elt = checkbox element
- var elt = e.element(),
- tr = elt.up('TR'),
- checked = $F(elt),
- end, start;
-
- if (this.startrange && e.shiftKey) {
- if (this.startrange != elt) {
- // Dirty trick - use position in page to determine which way
- // to traverse
- if (this.startrange.offsetTop < tr.offsetTop) {
- start = this.startrange.next();
- end = tr;
- } else {
- start = tr;
- end = this.startrange.previous();
- }
-
- do {
- this.selectRow(start, checked);
- if (start == end) {
- break;
- }
- start = start.next();
- } while (start);
- }
- } else {
- this.selectRow(tr, checked);
- }
-
- this.startrange = tr;
- },
-
- updateFolders: function(form)
- {
- var tm1 = $('targetMailbox1'),
- tm2 = $('targetMailbox2');
-
- if (tm2) {
- if ((form == 1 && $F(tm1) != "") ||
- (form == 2 && $F(tm2) != "")) {
- tm1.selectedIndex = tm2.selectedIndex = (form == 1)
- ? tm1.selectedIndex
- : tm2.selectedIndex;
- }
- }
- },
-
- _transfer: function(actID)
- {
- var newFolder, tmbox;
-
- if (this.anySelected()) {
- tmbox = $('targetMbox');
- tmbox.setValue($F('targetMailbox1'));
-
- // Check for a mailbox actually being selected.
- if ($F(tmbox) == '*new*') {
- newFolder = prompt(IMP.text.newfolder, '');
- if (newFolder != null && newFolder != '') {
- $('newMbox').setValue(1);
- tmbox.setValue(newFolder);
- this.submit(actID);
- }
- } else {
- if ($F(tmbox) == '') {
- alert(IMP.text.target_mbox);
- } else {
- this.submit(actID);
- }
- }
- } else {
- alert(IMP.text.mailbox_selectone);
- }
- },
-
- flagMessages: function(form)
- {
- var f1 = $('flag1'), f2 = $('flag2');
-
- if ((form == 1 && $F(f1) != "") ||
- (form == 2 && $F(f2) != "")) {
- if (this.anySelected()) {
- $('messages').down('[name=flag]').setValue((form == 1) ? $F(f1) : $F(f2));
- this.submit('flag_messages');
- } else {
- if (form == 1) {
- f1.selectedIndex = 0;
- } else {
- f2.selectedIndex = 0;
- }
- alert(IMP.text.mailbox_selectone);
- }
- }
- },
-
- getMessage: function(id, offset)
- {
- if (!offset) {
- return id;
- }
-
- var mlist = $H(this.messagelist).keys(),
- i = mlist.indexOf(id),
- j = i + offset;
-
- if (i != -1) {
- if (j >= 0 && j < mlist.length) {
- return mlist[j];
- }
- }
-
- return '';
- },
-
- changeHandler: function(e)
- {
- var id = e.element().readAttribute('id');
-
- if (id) {
- if (id.startsWith('flag')) {
- this.flagMessages(id.substring(4));
- } else if (id.startsWith('targetMailbox')) {
- this.updateFolders(id.substring(13));
- }
- }
- },
-
- clickHandler: function(e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = e.element(), id;
-
- while (Object.isElement(elt)) {
- if (elt.match('.msgactions A.widget')) {
- if (elt.hasClassName('moveAction')) {
- this._transfer('move_messages');
- } else if (elt.hasClassName('copyAction')) {
- this._transfer('copy_messages');
- } else if (elt.hasClassName('permdeleteAction')) {
- if (confirm(IMP.text.mailbox_delete)) {
- this.submit('delete_messages');
- }
- } else if (elt.hasClassName('deleteAction')) {
- this.submit('delete_messages');
- } else if (elt.hasClassName('undeleteAction')) {
- this.submit('undelete_messages');
- } else if (elt.hasClassName('blacklistAction')) {
- this.submit('blacklist');
- } else if (elt.hasClassName('whitelistAction')) {
- this.submit('whitelist');
- } else if (elt.hasClassName('forwardAction')) {
- this.submit('fwd_digest');
- } else if (elt.hasClassName('spamAction')) {
- this.submit('spam_report');
- } else if (elt.hasClassName('notspamAction')) {
- this.submit('notspam_report');
- } else if (elt.hasClassName('viewAction')) {
- this.submit('view_messages');
- } else if (elt.hasClassName('hideAction') || elt.hasClassName('purgeAction')) {
- return;
- }
-
- e.stop();
- return;
- } else if (elt.hasClassName('checkbox')) {
- this.selectRange(e);
- // Fall through to elt.up() call below.
- }
-
- id = elt.readAttribute('id');
- if (!id) {
- elt = elt.up();
- continue;
- }
-
- switch (id) {
- case 'checkheader':
- case 'checkAll':
- if (id == 'checkheader') {
- $('checkAll').checked = !$('checkAll').checked;
- }
-
- $('messages').select('TABLE.messageList TR[id]').each(function(i, s) {
- this.selectRow(i, $F('checkAll'));
- }, this);
- return;
- }
-
- if (!this.sortlimit &&
- elt.match('TH') &&
- elt.up('TABLE.messageList')) {
- document.location.href = elt.down('A').href;
- }
-
- elt = elt.up();
- }
- },
-
- keyDownHandler: function(e)
- {
- var elt = e.element(),
- key = e.keyCode,
- loc, search, tmp;
-
- if (e.altKey || e.ctrlKey) {
- if (!(key == Event.KEY_UP || key == Event.KEY_DOWN)) {
- return;
- }
-
- if (!this.cursor) {
- this.cursor = elt.up('TABLE.messageList TR');
- }
-
- if (this.cursor) {
- if (e.altKey) {
- this.selectRow(this.cursor, !$F(this.cursor.down('INPUT.checkbox')));
- }
-
- switch (key) {
- case Event.KEY_UP:
- this.cursor = this.cursor.previous();
- if (!this.cursor.readAttribute('id')) {
- search = 'last';
- }
- break;
-
- case Event.KEY_DOWN:
- this.cursor = this.cursor.next();
- if (!this.cursor) {
- search = 'first';
- }
- break;
- }
- } else {
- search = key == Event.KEY_DOWN ? 'first' : 'last';
- }
-
- if (search) {
- tmp = $('messages').select('TABLE.messageList TR[id]');
- this.cursor = (search == 'first') ? tmp.first() : tmp.last();
- }
-
- this.cursor.down('TD A.mboxSubject').focus();
- } else if (key == 32 && this.cursor) {
- this.selectRow(this.cursor, !$F(this.cursor.down('INPUT.checkbox')));
- } else if (!e.shiftKey) {
- if (key == Event.KEY_LEFT && $('prev')) {
- loc = $('prev');
- } else if (key == Event.KEY_RIGHT && $('next')) {
- loc = $('next');
- }
-
- if (loc) {
- document.location.href = loc.readAttribute('href');
- }
- return;
- } else {
- return;
- }
-
- e.stop();
- },
-
- submitHandler: function(e)
- {
- if (e.element().readAttribute('id').startsWith('select')) {
- e.stop();
- }
- }
-
-};
-
-document.observe('dom:loaded', function() {
- var im = ImpMailbox;
-
- document.observe('change', im.changeHandler.bindAsEventListener(im));
- document.observe('click', im.clickHandler.bindAsEventListener(im));
- document.observe('keydown', im.keyDownHandler.bindAsEventListener(im));
- document.observe('submit', im.submitHandler.bindAsEventListener(im));
-
- if (window.fluid) {
- try {
- window.fluid.setDockBadge(ImpMailbox.unread);
- } catch (e) {}
- }
-});
+++ /dev/null
-/**
- * Provides the javascript for the message.php script (standard view).
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var ImpMessage = {
-
- _arrowHandler: function(e)
- {
- if (e.altKey || e.shiftKey || e.ctrlKey) {
- return;
- }
-
- switch (e.keyCode || e.charCode) {
- case Event.KEY_LEFT:
- if ($('prev')) {
- document.location.href = $('prev').href;
- }
- break;
-
- case Event.KEY_RIGHT:
- if ($('next')) {
- document.location.href = $('next').href;
- }
- break;
- }
- },
-
- submit: function(actID)
- {
- switch (actID) {
- case 'spam_report':
- if (!window.confirm(IMP.text.spam_report)) {
- return;
- }
- break;
-
- case 'notspam_report':
- if (!window.confirm(IMP.text.notspam_report)) {
- return;
- }
- break;
- }
-
- $('actionID').setValue(actID);
- $('messages').submit();
- },
-
- flagMessage: function(form)
- {
- var f1 = $('flag1'), f2 = $('flag2');
-
- if ((form == 1 && $F(f1) != "") ||
- (form == 2 && $F(f2) != "")) {
- $('messages').down('[name=flag]').setValue((form == 1) ? $F(f1) : $F(f2));
- this.submit('flag_message');
- }
- },
-
- _transfer: function(actID)
- {
- var newFolder, tmbox = $('targetMbox');
- tmbox.setValue($F('target1'));
-
- // Check for a mailbox actually being selected.
- if ($F(tmbox) == '*new*') {
- newFolder = window.prompt(IMP.text.newfolder, '');
- if (newFolder != null && newFolder != '') {
- $('newMbox').setValue(1);
- tmbox.setValue(newFolder);
- this.submit(actID);
- }
- } else {
- if (!$F(tmbox)) {
- window.alert(IMP.text.target_mbox);
- } else {
- this.submit(actID);
- }
- }
- },
-
- updateFolders: function(form)
- {
- var f = (form == 1) ? 2 : 1;
- $('target' + f).selectedIndex = $('target' + form).selectedIndex;
- },
-
- /* Function needed for IE compatibilty with drop-down menus. */
- _messageActionsHover: function()
- {
- var iefix = new Element('IFRAME', { scrolling: 'no', frameborder: 0 }).setStyle({ position: 'absolute' }).hide();
-
- // This can not appear in the new Element() call - Bug #5887
- iefix.writeAttribute('src', 'javascript:false;');
-
- $$('UL.msgactions LI').each(function(li) {
- var fixcopy, ul = li.down('UL'), zindex;
- if (!ul) {
- return;
- }
-
- fixcopy = iefix.cloneNode(false);
- li.insert(fixcopy);
- fixcopy.clonePosition(ul);
-
- zindex = li.getStyle('zIndex');
- if (zindex == '') {
- li.setStyle({ zIndex: 2 });
- fixcopy.setStyle({ zIndex: 1 });
- } else {
- fixcopy.setStyle({ zIndex: parseInt(zindex) - 1 });
- }
-
- li.observe('mouseout', function() {
- this.removeClassName('hover');
- li.down('iframe').hide();
- });
- li.observe('mouseover', function() {
- this.addClassName('hover');
- li.down('iframe').show();
- });
- });
- },
-
- onDomLoad: function()
- {
- // Set up left and right arrows to go to the previous/next page.
- document.observe('keydown', this._arrowHandler.bindAsEventListener(this));
- document.observe('change', this._changeHandler.bindAsEventListener(this));
- document.observe('click', this._clickHandler.bindAsEventListener(this));
-
- if (Prototype.Browser.IE) {
- this._messageActionsHover();
- }
- },
-
- _changeHandler: function(e)
- {
- var id = e.element().readAttribute('id');
-
- if (id.startsWith('flag')) {
- this.flagMessage(id.substring(4));
- } else if (id.startsWith('target')) {
- this.updateFolders(id.substring(6));
- }
- },
-
- _clickHandler: function(e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = e.element();
-
- while (Object.isElement(elt)) {
- if (elt.match('.msgactions A.widget')) {
- if (elt.hasClassName('moveAction')) {
- this._transfer('move_message');
- } else if (elt.hasClassName('copyAction')) {
- this._transfer('copy_message');
- } else if (elt.hasClassName('spamAction')) {
- this.submit('spam_report');
- } else if (elt.hasClassName('notspamAction')) {
- this.submit('notspam_report');
- } else if (elt.hasClassName('printAction')) {
- window.print();
- }
- } else if (elt.hasClassName('unblockImageLink')) {
- IMP.unblockImages(e);
- } else if (elt.match('SPAN.toggleQuoteShow')) {
- [ elt, elt.next() ].invoke('toggle');
- Effect.BlindDown(elt.next(1), { duration: 0.2, queue: { position: 'end', scope: 'showquote', limit: 2 } });
- } else if (elt.match('SPAN.toggleQuoteHide')) {
- [ elt, elt.previous() ].invoke('toggle');
- Effect.BlindUp(elt.next(), { duration: 0.2, queue: { position: 'end', scope: 'showquote', limit: 2 } });
- }
-
- elt = elt.up();
- }
- }
-
-};
-
-document.observe('dom:loaded', ImpMessage.onDomLoad.bind(ImpMessage));
+++ /dev/null
-/**
- * Provides the javascript for the search.php script (standard view).
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var ImpSearch = {
- // The following variables are defined in search.php:
- // inverse_sub, not_search, search_date
-
- _toggleAll: function(checked)
- {
- $('search').getInputs(null, 'search_folders[]').each(function(e) {
- e.checked = checked;
- });
- },
-
- _dateCheck: function(field)
- {
- var m = $('search_' + field + '_month'),
- d = $('search_' + field + '_day'),
- y = $('search_' + field + '_year');
-
- if (m.selectedIndex == 0) {
- m.selectedIndex = this.search_date.m;
- }
-
- if (d.selectedIndex == 0) {
- d.selectedIndex = this.search_date.d;
- }
-
- if (y.value == "") {
- y.value = this.search_date.y;
- }
- },
-
- _formCheck: function()
- {
- if (this.not_search &&
- (!$('preselected_folders') || !$F('preselected_folders'))) {
- if (!Form.getInputs('search', null, 'search_folders[]').detect(function(e) { return e.checked; })) {
- alert(IMP.text.search_select);
- return;
- }
- }
-
- $('actionID').setValue('do_search');
- },
-
- _reset: function()
- {
- $('actionID').setValue('reset_search');
- $('search').submit();
- },
-
- _saveCache: function()
- {
- $('edit_query').setValue($F('save_cache'));
- $('search').submit();
- },
-
- _deleteField: function(i)
- {
- $('delete_field_id').setValue(i);
- $('actionID').setValue('delete_field');
- $('search').submit();
- },
-
- _showSubscribed: function(i)
- {
- $('show_subscribed_only').setValue(i);
- $('search').submit();
- },
-
- changeHandler: function(e)
- {
- var id = e.element().readAttribute('id');
-
- switch (id) {
- case 'save_cache':
- this._saveCache();
- break;
-
- default:
- if (id.startsWith('field_')) {
- $('search').submit();
- } else if (id.startsWith('search_date_')) {
- this._dateCheck('on');
- }
- break;
- }
- },
-
- clickHandler: function(e)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = e.element();
-
- while (Object.isElement(elt)) {
- if (elt.hasClassName('searchSubmit')) {
- this._formCheck();
- } else if (elt.hasClassName('searchReset')) {
- this._reset();
- } else if (elt.hasClassName('searchDelete')) {
- this._deleteField(elt.readAttribute('fid'));
- } else {
- switch (elt.readAttribute('id')) {
- case 'link_sel_all':
- this._toggleAll(true);
- break;
-
- case 'link_sel_none':
- this._toggleAll(false);
- break;
-
- case 'link_sub':
- this._showSubscribed(this.inverse_sub);
- break;
-
- case 'search_match_and':
- case 'search_match_or':
- if ($('field_1')) {
- $('search').submit();
- }
- break;
- }
- }
-
- elt = elt.up();
- }
- }
-
-};
-
-document.observe('change', ImpSearch.changeHandler.bind(ImpSearch));
-document.observe('click', ImpSearch.clickHandler.bind(ImpSearch));
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ar-SY",
+ englishName: "Arabic (Syria)",
+ nativeName: "العربية (سوريا)",
+
+ /* Day Name Strings */
+ dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
+ shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+ firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
+
+ /* Month Name Strings */
+ monthNames: ["كانون الثاني", "شباط", "آذار", "نيسان", "أيار", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول"],
+ abbreviatedMonthNames: ["كانون الثاني", "شباط", "آذار", "نيسان", "أيار", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول"],
+
+ /* AM/PM Designators */
+ amDesignator: "ص",
+ pmDesignator: "م",
+
+ firstDayOfWeek: 6,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^كانون الثاني/i,
+ feb: /^شباط/i,
+ mar: /^آذار/i,
+ apr: /^نيسان/i,
+ may: /^أيار/i,
+ jun: /^حزيران/i,
+ jul: /^تموز/i,
+ aug: /^آب/i,
+ sep: /^أيلول/i,
+ oct: /^تشرين الأول/i,
+ nov: /^تشرين الثاني/i,
+ dec: /^كانون الأول/i,
+
+ sun: /^الاحد/i,
+ mon: /^ا(1)?/i,
+ tue: /^الثلاثاء/i,
+ wed: /^الاربعاء/i,
+ thu: /^الخميس/i,
+ fri: /^الجمعة/i,
+ sat: /^السبت/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "bg-BG",
+ englishName: "Bulgarian (Bulgaria)",
+ nativeName: "български (България)",
+
+ /* Day Name Strings */
+ dayNames: ["неделя", "понеделник", "вторник", "сряда", "четвъртък", "петък", "събота"],
+ abbreviatedDayNames: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
+ shortestDayNames: ["не", "по", "вт", "ср", "че", "пе", "съ"],
+ firstLetterDayNames: ["н", "п", "в", "с", "ч", "п", "с"],
+
+ /* Month Name Strings */
+ monthNames: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"],
+ abbreviatedMonthNames: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.M.yyyy 'г.'",
+ longDate: "dd MMMM yyyy 'г.'",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy 'г.' HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy 'г.'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^януари/i,
+ feb: /^февруари/i,
+ mar: /^март/i,
+ apr: /^април/i,
+ may: /^май/i,
+ jun: /^юни/i,
+ jul: /^юли/i,
+ aug: /^август/i,
+ sep: /^септември/i,
+ oct: /^октомври/i,
+ nov: /^ноември/i,
+ dec: /^декември/i,
+
+ sun: /^не((деля)?)?/i,
+ mon: /^по((неделник)?)?/i,
+ tue: /^вторник/i,
+ wed: /^сряда/i,
+ thu: /^че((твъртък)?)?/i,
+ fri: /^пе((тък)?)?/i,
+ sat: /^съ((бота)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "bs-Latn-BA",
+ englishName: "Bosnian (Bosnia and Herzegovina)",
+ nativeName: "bosanski (Bosna i Hercegovina)",
+
+ /* Day Name Strings */
+ dayNames: ["nedjelja", "ponedjeljak", "utorak", "srijeda", "četvrtak", "petak", "subota"],
+ abbreviatedDayNames: ["ned", "pon", "uto", "sri", "čet", "pet", "sub"],
+ shortestDayNames: ["ned", "pon", "uto", "sri", "čet", "pet", "sub"],
+ firstLetterDayNames: ["n", "p", "u", "s", "č", "p", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["januar", "februar", "mart", "april", "maj", "jun", "jul", "avgust", "septembar", "oktobar", "novembar", "decembar"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "avg", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm:ss",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mar(t)?/i,
+ apr: /^apr(il)?/i,
+ may: /^maj/i,
+ jun: /^jun/i,
+ jul: /^jul/i,
+ aug: /^avg(ust)?/i,
+ sep: /^sep(tembar)?/i,
+ oct: /^okt(obar)?/i,
+ nov: /^nov(embar)?/i,
+ dec: /^dec(embar)?/i,
+
+ sun: /^nedjelja/i,
+ mon: /^ponedjeljak/i,
+ tue: /^utorak/i,
+ wed: /^srijeda/i,
+ thu: /^četvrtak/i,
+ fri: /^petak/i,
+ sat: /^subota/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ca-ES",
+ englishName: "Catalan (Catalan)",
+ nativeName: "català (català)",
+
+ /* Day Name Strings */
+ dayNames: ["diumenge", "dilluns", "dimarts", "dimecres", "dijous", "divendres", "dissabte"],
+ abbreviatedDayNames: ["dg.", "dl.", "dt.", "dc.", "dj.", "dv.", "ds."],
+ shortestDayNames: ["dg", "dl", "dt", "dc", "dj", "dv", "ds"],
+ firstLetterDayNames: ["d", "d", "d", "d", "d", "d", "d"],
+
+ /* Month Name Strings */
+ monthNames: ["gener", "febrer", "març", "abril", "maig", "juny", "juliol", "agost", "setembre", "octubre", "novembre", "desembre"],
+ abbreviatedMonthNames: ["gen", "feb", "març", "abr", "maig", "juny", "jul", "ag", "set", "oct", "nov", "des"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, d' / 'MMMM' / 'yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, d' / 'MMMM' / 'yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' / 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^gen(er)?/i,
+ feb: /^feb(rer)?/i,
+ mar: /^març/i,
+ apr: /^abr(il)?/i,
+ may: /^maig/i,
+ jun: /^juny/i,
+ jul: /^jul(iol)?/i,
+ aug: /^ag(ost)?/i,
+ sep: /^set(embre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(embre)?/i,
+ dec: /^des(embre)?/i,
+
+ sun: /^dg((.(umenge)?)?)?/i,
+ mon: /^dl((.(lluns)?)?)?/i,
+ tue: /^dt((.(marts)?)?)?/i,
+ wed: /^dc((.(mecres)?)?)?/i,
+ thu: /^dj((.(jous)?)?)?/i,
+ fri: /^dv((.(vendres)?)?)?/i,
+ sat: /^ds((.(ssabte)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+function sbarToggle()
+{
+ var body = $(document.body), pref_value;
+
+ if (body.hasClassName('rightPanel')) {
+ pref_value = 0;
+ body.removeClassName('rightPanel');
+ } else {
+ pref_value = 1;
+ body.addClassName('rightPanel');
+ }
+
+ new Ajax.Request(KronolithVar.pref_api_url, { parameters: { app: 'kronolith', pref: 'show_panel', value: pref_value } });
+}
+
+function removeTag(tagid)
+{
+
+}
+document.observe('dom:loaded', function() {
+ $$('#pageControlsInner .checkbox').invoke('observe', 'click', function() {
+ Views.invalidate();
+ ShowView(kronolithView, { date: kronolithDate.getFullYear() + (kronolithDate.getMonth() + 1).toPaddedString(2) + kronolithDate.getDate().toPaddedString(2), toggle_calendar: this.value }, false);
+ });
+
+ $$('#pageControlsInner .calendar-info').invoke('observe', 'click', function() {
+ RedBox.loading();
+ var calendar_id = this.up().select('.checkbox').first().value;
+ new Ajax.Request(KronolithVar.calendar_info_url, {
+ parameters: { c: calendar_id },
+ method: 'get',
+ onSuccess: function(transport) {
+ RedBox.showHtml('<div id="RB_info">' + transport.responseText + '<input type="button" class="button" onclick="RedBox.close();" value="' + KronolithText.close + '" /></div>');
+ },
+ onFailure: function(transport) {
+ RedBox.close();
+ }
+ });
+ });
+});
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "cs-CZ",
+ englishName: "Czech (Czech Republic)",
+ nativeName: "čeština (Česká republika)",
+
+ /* Day Name Strings */
+ dayNames: ["neděle", "pondělí", "úterý", "středa", "čtvrtek", "pátek", "sobota"],
+ abbreviatedDayNames: ["ne", "po", "út", "st", "čt", "pá", "so"],
+ shortestDayNames: ["ne", "po", "út", "st", "čt", "pá", "so"],
+ firstLetterDayNames: ["n", "p", "ú", "s", "č", "p", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["leden", "únor", "březen", "duben", "květen", "červen", "červenec", "srpen", "září", "říjen", "listopad", "prosinec"],
+ abbreviatedMonthNames: ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"],
+
+ /* AM/PM Designators */
+ amDesignator: "dop.",
+ pmDesignator: "odp.",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^leden/i,
+ feb: /^únor/i,
+ mar: /^březen/i,
+ apr: /^duben/i,
+ may: /^květen/i,
+ jun: /^červen/i,
+ jul: /^červenec/i,
+ aug: /^srpen/i,
+ sep: /^září/i,
+ oct: /^říjen/i,
+ nov: /^listopad/i,
+ dec: /^prosinec/i,
+
+ sun: /^neděle/i,
+ mon: /^pondělí/i,
+ tue: /^úterý/i,
+ wed: /^středa/i,
+ thu: /^čtvrtek/i,
+ fri: /^pátek/i,
+ sat: /^sobota/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "da-DK",
+ englishName: "Danish (Denmark)",
+ nativeName: "dansk (Danmark)",
+
+ /* Day Name Strings */
+ dayNames: ["søndag", "mandag", "tirsdag", "onsdag", "torsdag", "fredag", "lørdag"],
+ abbreviatedDayNames: ["sø", "ma", "ti", "on", "to", "fr", "lø"],
+ shortestDayNames: ["sø", "ma", "ti", "on", "to", "fr", "lø"],
+ firstLetterDayNames: ["s", "m", "t", "o", "t", "f", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["januar", "februar", "marts", "april", "maj", "juni", "juli", "august", "september", "oktober", "november", "december"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mar(ts)?/i,
+ apr: /^apr(il)?/i,
+ may: /^maj/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^søndag/i,
+ mon: /^mandag/i,
+ tue: /^tirsdag/i,
+ wed: /^onsdag/i,
+ thu: /^torsdag/i,
+ fri: /^fredag/i,
+ sat: /^lørdag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+/**
+ * @version: 1.0 Alpha-1
+ * @author: Coolite Inc. http://www.coolite.com/
+ * @date: 2008-04-13
+ * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
+ * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
+ * @website: http://www.datejs.com/
+ */
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ $C = $D.CultureInfo,
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+
+ /**
+ * Resets the time of this Date object to 12:00 AM (00:00), which is the start of the day.
+ * @param {Boolean} .clone() this date instance before clearing Time
+ * @return {Date} this
+ */
+ $P.clearTime = function () {
+ this.setHours(0);
+ this.setMinutes(0);
+ this.setSeconds(0);
+ this.setMilliseconds(0);
+ return this;
+ };
+
+ /**
+ * Resets the time of this Date object to the current time ('now').
+ * @return {Date} this
+ */
+ $P.setTimeToNow = function () {
+ var n = new Date();
+ this.setHours(n.getHours());
+ this.setMinutes(n.getMinutes());
+ this.setSeconds(n.getSeconds());
+ this.setMilliseconds(n.getMilliseconds());
+ return this;
+ };
+
+ /**
+ * Gets a date that is set to the current date. The time is set to the start of the day (00:00 or 12:00 AM).
+ * @return {Date} The current date.
+ */
+ $D.today = function () {
+ return new Date().clearTime();
+ };
+
+ /**
+ * Compares the first date to the second date and returns an number indication of their relative values.
+ * @param {Date} First Date object to compare [Required].
+ * @param {Date} Second Date object to compare to [Required].
+ * @return {Number} -1 = date1 is lessthan date2. 0 = values are equal. 1 = date1 is greaterthan date2.
+ */
+ $D.compare = function (date1, date2) {
+ if (isNaN(date1) || isNaN(date2)) {
+ throw new Error(date1 + " - " + date2);
+ } else if (date1 instanceof Date && date2 instanceof Date) {
+ return (date1 < date2) ? -1 : (date1 > date2) ? 1 : 0;
+ } else {
+ throw new TypeError(date1 + " - " + date2);
+ }
+ };
+
+ /**
+ * Compares the first Date object to the second Date object and returns true if they are equal.
+ * @param {Date} First Date object to compare [Required]
+ * @param {Date} Second Date object to compare to [Required]
+ * @return {Boolean} true if dates are equal. false if they are not equal.
+ */
+ $D.equals = function (date1, date2) {
+ return (date1.compareTo(date2) === 0);
+ };
+
+ /**
+ * Gets the day number (0-6) if given a CultureInfo specific string which is a valid dayName, abbreviatedDayName or shortestDayName (two char).
+ * @param {String} The name of the day (eg. "Monday, "Mon", "tuesday", "tue", "We", "we").
+ * @return {Number} The day number
+ */
+ $D.getDayNumberFromName = function (name) {
+ var n = $C.dayNames, m = $C.abbreviatedDayNames, o = $C.shortestDayNames, s = name.toLowerCase();
+ for (var i = 0; i < n.length; i++) {
+ if (n[i].toLowerCase() == s || m[i].toLowerCase() == s || o[i].toLowerCase() == s) {
+ return i;
+ }
+ }
+ return -1;
+ };
+
+ /**
+ * Gets the month number (0-11) if given a Culture Info specific string which is a valid monthName or abbreviatedMonthName.
+ * @param {String} The name of the month (eg. "February, "Feb", "october", "oct").
+ * @return {Number} The day number
+ */
+ $D.getMonthNumberFromName = function (name) {
+ var n = $C.monthNames, m = $C.abbreviatedMonthNames, s = name.toLowerCase();
+ for (var i = 0; i < n.length; i++) {
+ if (n[i].toLowerCase() == s || m[i].toLowerCase() == s) {
+ return i;
+ }
+ }
+ return -1;
+ };
+
+ /**
+ * Determines if the current date instance is within a LeapYear.
+ * @param {Number} The year.
+ * @return {Boolean} true if date is within a LeapYear, otherwise false.
+ */
+ $D.isLeapYear = function (year) {
+ return ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);
+ };
+
+ /**
+ * Gets the number of days in the month, given a year and month value. Automatically corrects for LeapYear.
+ * @param {Number} The year.
+ * @param {Number} The month (0-11).
+ * @return {Number} The number of days in the month.
+ */
+ $D.getDaysInMonth = function (year, month) {
+ return [31, ($D.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
+ };
+
+ $D.getTimezoneAbbreviation = function (offset) {
+ var z = $C.timezones, p;
+ for (var i = 0; i < z.length; i++) {
+ if (z[i].offset === offset) {
+ return z[i].name;
+ }
+ }
+ return null;
+ };
+
+ $D.getTimezoneOffset = function (name) {
+ var z = $C.timezones, p;
+ for (var i = 0; i < z.length; i++) {
+ if (z[i].name === name.toUpperCase()) {
+ return z[i].offset;
+ }
+ }
+ return null;
+ };
+
+ /**
+ * Returns a new Date object that is an exact date and time copy of the original instance.
+ * @return {Date} A new Date instance
+ */
+ $P.clone = function () {
+ return new Date(this.getTime());
+ };
+
+ /**
+ * Compares this instance to a Date object and returns an number indication of their relative values.
+ * @param {Date} Date object to compare [Required]
+ * @return {Number} -1 = this is lessthan date. 0 = values are equal. 1 = this is greaterthan date.
+ */
+ $P.compareTo = function (date) {
+ return Date.compare(this, date);
+ };
+
+ /**
+ * Compares this instance to another Date object and returns true if they are equal.
+ * @param {Date} Date object to compare. If no date to compare, new Date() [now] is used.
+ * @return {Boolean} true if dates are equal. false if they are not equal.
+ */
+ $P.equals = function (date) {
+ return Date.equals(this, date || new Date());
+ };
+
+ /**
+ * Determines if this instance is between a range of two dates or equal to either the start or end dates.
+ * @param {Date} Start of range [Required]
+ * @param {Date} End of range [Required]
+ * @return {Boolean} true is this is between or equal to the start and end dates, else false
+ */
+ $P.between = function (start, end) {
+ return this.getTime() >= start.getTime() && this.getTime() <= end.getTime();
+ };
+
+ /**
+ * Determines if this date occurs after the date to compare to.
+ * @param {Date} Date object to compare. If no date to compare, new Date() ("now") is used.
+ * @return {Boolean} true if this date instance is greater than the date to compare to (or "now"), otherwise false.
+ */
+ $P.isAfter = function (date) {
+ return this.compareTo(date || new Date()) === 1;
+ };
+
+ /**
+ * Determines if this date occurs before the date to compare to.
+ * @param {Date} Date object to compare. If no date to compare, new Date() ("now") is used.
+ * @return {Boolean} true if this date instance is less than the date to compare to (or "now").
+ */
+ $P.isBefore = function (date) {
+ return (this.compareTo(date || new Date()) === -1);
+ };
+
+ /**
+ * Determines if the current Date instance occurs today.
+ * @return {Boolean} true if this date instance is 'today', otherwise false.
+ */
+
+ /**
+ * Determines if the current Date instance occurs on the same Date as the supplied 'date'.
+ * If no 'date' to compare to is provided, the current Date instance is compared to 'today'.
+ * @param {date} Date object to compare. If no date to compare, the current Date ("now") is used.
+ * @return {Boolean} true if this Date instance occurs on the same Day as the supplied 'date'.
+ */
+ $P.isToday = $P.isSameDay = function (date) {
+ return this.clone().clearTime().equals((date || new Date()).clone().clearTime());
+ };
+
+ /**
+ * Adds the specified number of milliseconds to this instance.
+ * @param {Number} The number of milliseconds to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addMilliseconds = function (value) {
+ this.setMilliseconds(this.getMilliseconds() + value * 1);
+ return this;
+ };
+
+ /**
+ * Adds the specified number of seconds to this instance.
+ * @param {Number} The number of seconds to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addSeconds = function (value) {
+ return this.addMilliseconds(value * 1000);
+ };
+
+ /**
+ * Adds the specified number of seconds to this instance.
+ * @param {Number} The number of seconds to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addMinutes = function (value) {
+ return this.addMilliseconds(value * 60000); /* 60*1000 */
+ };
+
+ /**
+ * Adds the specified number of hours to this instance.
+ * @param {Number} The number of hours to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addHours = function (value) {
+ return this.addMilliseconds(value * 3600000); /* 60*60*1000 */
+ };
+
+ /**
+ * Adds the specified number of days to this instance.
+ * @param {Number} The number of days to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addDays = function (value) {
+ this.setDate(this.getDate() + value * 1);
+ return this;
+ };
+
+ /**
+ * Adds the specified number of weeks to this instance.
+ * @param {Number} The number of weeks to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addWeeks = function (value) {
+ return this.addDays(value * 7);
+ };
+
+ /**
+ * Adds the specified number of months to this instance.
+ * @param {Number} The number of months to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addMonths = function (value) {
+ var n = this.getDate();
+ this.setDate(1);
+ this.setMonth(this.getMonth() + value * 1);
+ this.setDate(Math.min(n, $D.getDaysInMonth(this.getFullYear(), this.getMonth())));
+ return this;
+ };
+
+ /**
+ * Adds the specified number of years to this instance.
+ * @param {Number} The number of years to add. The number can be positive or negative [Required]
+ * @return {Date} this
+ */
+ $P.addYears = function (value) {
+ return this.addMonths(value * 12);
+ };
+
+ /**
+ * Adds (or subtracts) to the value of the years, months, weeks, days, hours, minutes, seconds, milliseconds of the date instance using given configuration object. Positive and Negative values allowed.
+ * Example
+ <pre><code>
+ Date.today().add( { days: 1, months: 1 } )
+
+ new Date().add( { years: -1 } )
+ </code></pre>
+ * @param {Object} Configuration object containing attributes (months, days, etc.)
+ * @return {Date} this
+ */
+ $P.add = function (config) {
+ if (typeof config == "number") {
+ this._orient = config;
+ return this;
+ }
+
+ var x = config;
+
+ if (x.milliseconds) {
+ this.addMilliseconds(x.milliseconds);
+ }
+ if (x.seconds) {
+ this.addSeconds(x.seconds);
+ }
+ if (x.minutes) {
+ this.addMinutes(x.minutes);
+ }
+ if (x.hours) {
+ this.addHours(x.hours);
+ }
+ if (x.weeks) {
+ this.addWeeks(x.weeks);
+ }
+ if (x.months) {
+ this.addMonths(x.months);
+ }
+ if (x.years) {
+ this.addYears(x.years);
+ }
+ if (x.days) {
+ this.addDays(x.days);
+ }
+ return this;
+ };
+
+ var $y, $m, $d;
+
+ /**
+ * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * This algorithm is a JavaScript port of the work presented by Claus Tøndering at http://www.tondering.dk/claus/cal/node8.html#SECTION00880000000000000000
+ * .getWeek() Algorithm Copyright (c) 2008 Claus Tondering.
+ * The .getWeek() function does NOT convert the date to UTC. The local datetime is used. Please use .getISOWeek() to get the week of the UTC converted date.
+ * @return {Number} 1 to 53
+ */
+ $P.getWeek = function () {
+ var a, b, c, d, e, f, g, n, s, w;
+
+ $y = (!$y) ? this.getFullYear() : $y;
+ $m = (!$m) ? this.getMonth() + 1 : $m;
+ $d = (!$d) ? this.getDate() : $d;
+
+ if ($m <= 2) {
+ a = $y - 1;
+ b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0);
+ c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0);
+ s = b - c;
+ e = 0;
+ f = $d - 1 + (31 * ($m - 1));
+ } else {
+ a = $y;
+ b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0);
+ c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0);
+ s = b - c;
+ e = s + 1;
+ f = $d + ((153 * ($m - 3) + 2) / 5 | 0) + 58 + s;
+ }
+
+ g = (a + b) % 7;
+ d = (f + g - e) % 7;
+ n = f + 3 - d;
+
+ if (n < 0) {
+ w = 53 - ((g - s) / 5 | 0);
+ } else if (n > 364 + s) {
+ w = 1;
+ } else {
+ w = (n / 7 | 0) + 1;
+ }
+
+ $y = $m = $d = null;
+
+ return w;
+ };
+
+ /**
+ * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
+ * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
+ * @return {String} "01" to "53"
+ */
+ $P.getISOWeek = function () {
+ $y = this.getUTCFullYear();
+ $m = this.getUTCMonth() + 1;
+ $d = this.getUTCDate();
+ return p(this.getWeek());
+ };
+
+ /**
+ * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
+ * @param {Number} A Number (1 to 53) that represents the week of the year.
+ * @return {Date} this
+ */
+ $P.setWeek = function (n) {
+ return this.moveToDayOfWeek(1).addWeeks(n - this.getWeek());
+ };
+
+ // private
+ var validate = function (n, min, max, name) {
+ if (typeof n == "undefined") {
+ return false;
+ } else if (typeof n != "number") {
+ throw new TypeError(n + " is not a Number.");
+ } else if (n < min || n > max) {
+ throw new RangeError(n + " is not a valid value for " + name + ".");
+ }
+ return true;
+ };
+
+ /**
+ * Validates the number is within an acceptable range for milliseconds [0-999].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateMillisecond = function (value) {
+ return validate(value, 0, 999, "millisecond");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for seconds [0-59].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateSecond = function (value) {
+ return validate(value, 0, 59, "second");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for minutes [0-59].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateMinute = function (value) {
+ return validate(value, 0, 59, "minute");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for hours [0-23].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateHour = function (value) {
+ return validate(value, 0, 23, "hour");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for the days in a month [0-MaxDaysInMonth].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateDay = function (value, year, month) {
+ return validate(value, 1, $D.getDaysInMonth(year, month), "day");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for months [0-11].
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateMonth = function (value) {
+ return validate(value, 0, 11, "month");
+ };
+
+ /**
+ * Validates the number is within an acceptable range for years.
+ * @param {Number} The number to check if within range.
+ * @return {Boolean} true if within range, otherwise false.
+ */
+ $D.validateYear = function (value) {
+ return validate(value, 0, 9999, "year");
+ };
+
+ /**
+ * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
+ * Example
+ <pre><code>
+ Date.today().set( { day: 20, month: 1 } )
+
+ new Date().set( { millisecond: 0 } )
+ </code></pre>
+ *
+ * @param {Object} Configuration object containing attributes (month, day, etc.)
+ * @return {Date} this
+ */
+ $P.set = function (config) {
+ if ($D.validateMillisecond(config.millisecond)) {
+ this.addMilliseconds(config.millisecond - this.getMilliseconds());
+ }
+
+ if ($D.validateSecond(config.second)) {
+ this.addSeconds(config.second - this.getSeconds());
+ }
+
+ if ($D.validateMinute(config.minute)) {
+ this.addMinutes(config.minute - this.getMinutes());
+ }
+
+ if ($D.validateHour(config.hour)) {
+ this.addHours(config.hour - this.getHours());
+ }
+
+ if ($D.validateMonth(config.month)) {
+ this.addMonths(config.month - this.getMonth());
+ }
+
+ if ($D.validateYear(config.year)) {
+ this.addYears(config.year - this.getFullYear());
+ }
+
+ /* day has to go last because you can't validate the day without first knowing the month */
+ if ($D.validateDay(config.day, this.getFullYear(), this.getMonth())) {
+ this.addDays(config.day - this.getDate());
+ }
+
+ if (config.timezone) {
+ this.setTimezone(config.timezone);
+ }
+
+ if (config.timezoneOffset) {
+ this.setTimezoneOffset(config.timezoneOffset);
+ }
+
+ if (config.week && validate(config.week, 0, 53, "week")) {
+ this.setWeek(config.week);
+ }
+
+ return this;
+ };
+
+ /**
+ * Moves the date to the first day of the month.
+ * @return {Date} this
+ */
+ $P.moveToFirstDayOfMonth = function () {
+ return this.set({ day: 1 });
+ };
+
+ /**
+ * Moves the date to the last day of the month.
+ * @return {Date} this
+ */
+ $P.moveToLastDayOfMonth = function () {
+ return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
+ };
+
+ /**
+ * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
+ * @return {Date} this
+ */
+ $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
+ var shift = 0;
+ if (occurrence > 0) {
+ shift = occurrence - 1;
+ }
+ else if (occurrence === -1) {
+ this.moveToLastDayOfMonth();
+ if (this.getDay() !== dayOfWeek) {
+ this.moveToDayOfWeek(dayOfWeek, -1);
+ }
+ return this;
+ }
+ return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
+ };
+
+ /**
+ * Move to the next or last dayOfWeek based on the orient value.
+ * @param {Number} The dayOfWeek to move to
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToDayOfWeek = function (dayOfWeek, orient) {
+ var diff = (dayOfWeek - this.getDay() + 7 * (orient || +1)) % 7;
+ return this.addDays((diff === 0) ? diff += 7 * (orient || +1) : diff);
+ };
+
+ /**
+ * Move to the next or last month based on the orient value.
+ * @param {Number} The month to move to. 0 = January, 11 = December
+ * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
+ * @return {Date} this
+ */
+ $P.moveToMonth = function (month, orient) {
+ var diff = (month - this.getMonth() + 12 * (orient || +1)) % 12;
+ return this.addMonths((diff === 0) ? diff += 12 * (orient || +1) : diff);
+ };
+
+ /**
+ * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
+ * @return {Number} 1 through 365 (366 in leap years)
+ */
+ $P.getOrdinalNumber = function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ };
+
+ /**
+ * Get the time zone abbreviation of the current date.
+ * @return {String} The abbreviated time zone name (e.g. "EST")
+ */
+ $P.getTimezone = function () {
+ return $D.getTimezoneAbbreviation(this.getUTCOffset());
+ };
+
+ $P.setTimezoneOffset = function (offset) {
+ var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
+ return this.addMinutes(there - here);
+ };
+
+ $P.setTimezone = function (offset) {
+ return this.setTimezoneOffset($D.getTimezoneOffset(offset));
+ };
+
+ /**
+ * Indicates whether Daylight Saving Time is observed in the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.hasDaylightSavingTime = function () {
+ return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
+ };
+
+ /**
+ * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
+ * @return {Boolean} true|false
+ */
+ $P.isDaylightSavingTime = function () {
+ return Date.today().set({month: 0, day: 1}).getTimezoneOffset() != this.getTimezoneOffset();
+ };
+
+ /**
+ * Get the offset from UTC of the current date.
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
+ */
+ $P.getUTCOffset = function () {
+ var n = this.getTimezoneOffset() * -10 / 6, r;
+ if (n < 0) {
+ r = (n - 10000).toString();
+ return r.charAt(0) + r.substr(2);
+ } else {
+ r = (n + 10000).toString();
+ return "+" + r.substr(1);
+ }
+ };
+
+ /**
+ * Returns the number of milliseconds between this date and date.
+ * @param {Date} Defaults to now
+ * @return {Number} The diff in milliseconds
+ */
+ $P.getElapsed = function (date) {
+ return (date || new Date()) - this;
+ };
+
+ if (!$P.toISOString) {
+ /**
+ * Converts the current date instance into a string with an ISO 8601 format. The date is converted to it's UTC value.
+ * @return {String} ISO 8601 string of date
+ */
+ $P.toISOString = function () {
+ // From http://www.json.org/json.js. Public Domain.
+ function f(n) {
+ return n < 10 ? '0' + n : n;
+ }
+
+ return '"' + this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z"';
+ };
+ }
+
+ // private
+ $P._toString = $P.toString;
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation.
+ * Format Specifiers
+ <pre>
+ CUSTOM DATE AND TIME FORMAT STRINGS
+ Format Description Example
+ ------ --------------------------------------------------------------------------- -----------------------
+ s The seconds of the minute between 0-59. "0" to "59"
+ ss The seconds of the minute with leading zero if required. "00" to "59"
+
+ m The minute of the hour between 0-59. "0" or "59"
+ mm The minute of the hour with leading zero if required. "00" or "59"
+
+ h The hour of the day between 1-12. "1" to "12"
+ hh The hour of the day with leading zero if required. "01" to "12"
+
+ H The hour of the day between 0-23. "0" to "23"
+ HH The hour of the day with leading zero if required. "00" to "23"
+
+ d The day of the month between 1 and 31. "1" to "31"
+ dd The day of the month with leading zero if required. "01" to "31"
+ ddd Abbreviated day name. $C.abbreviatedDayNames. "Mon" to "Sun"
+ dddd The full day name. $C.dayNames. "Monday" to "Sunday"
+
+ M The month of the year between 1-12. "1" to "12"
+ MM The month of the year with leading zero if required. "01" to "12"
+ MMM Abbreviated month name. $C.abbreviatedMonthNames. "Jan" to "Dec"
+ MMMM The full month name. $C.monthNames. "January" to "December"
+
+ yy The year as a two-digit number. "99" or "08"
+ yyyy The full four digit year. "1999" or "2008"
+
+ t Displays the first character of the A.M./P.M. designator. "A" or "P"
+ $C.amDesignator or $C.pmDesignator
+ tt Displays the A.M./P.M. designator. "AM" or "PM"
+ $C.amDesignator or $C.pmDesignator
+
+ S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
+
+|| *Format* || *Description* || *Example* ||
+|| d || The CultureInfo shortDate Format Pattern || "M/d/yyyy" ||
+|| D || The CultureInfo longDate Format Pattern || "dddd, MMMM dd, yyyy" ||
+|| F || The CultureInfo fullDateTime Format Pattern || "dddd, MMMM dd, yyyy h:mm:ss tt" ||
+|| m || The CultureInfo monthDay Format Pattern || "MMMM dd" ||
+|| r || The CultureInfo rfc1123 Format Pattern || "ddd, dd MMM yyyy HH:mm:ss GMT" ||
+|| s || The CultureInfo sortableDateTime Format Pattern || "yyyy-MM-ddTHH:mm:ss" ||
+|| t || The CultureInfo shortTime Format Pattern || "h:mm tt" ||
+|| T || The CultureInfo longTime Format Pattern || "h:mm:ss tt" ||
+|| u || The CultureInfo universalSortableDateTime Format Pattern || "yyyy-MM-dd HH:mm:ssZ" ||
+|| y || The CultureInfo yearMonth Format Pattern || "MMMM, yyyy" ||
+
+
+ STANDARD DATE AND TIME FORMAT STRINGS
+ Format Description Example ("en-US")
+ ------ --------------------------------------------------------------------------- -----------------------
+ d The CultureInfo shortDate Format Pattern "M/d/yyyy"
+ D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
+ F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
+ m The CultureInfo monthDay Format Pattern "MMMM dd"
+ r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
+ s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
+ t The CultureInfo shortTime Format Pattern "h:mm tt"
+ T The CultureInfo longTime Format Pattern "h:mm:ss tt"
+ u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
+ y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
+ </pre>
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ $P.toString = function (format) {
+ var x = this;
+
+ // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
+ // may vary by culture.
+ if (format && format.length == 1) {
+ var c = $C.formatPatterns;
+ x.t = x.toString;
+ switch (format) {
+ case "d":
+ return x.t(c.shortDate);
+ case "D":
+ return x.t(c.longDate);
+ case "F":
+ return x.t(c.fullDateTime);
+ case "m":
+ return x.t(c.monthDay);
+ case "r":
+ return x.t(c.rfc1123);
+ case "s":
+ return x.t(c.sortableDateTime);
+ case "t":
+ return x.t(c.shortTime);
+ case "T":
+ return x.t(c.longTime);
+ case "u":
+ return x.t(c.universalSortableDateTime);
+ case "y":
+ return x.t(c.yearMonth);
+ }
+ }
+
+ var ord = function (n) {
+ switch (n * 1) {
+ case 1:
+ case 21:
+ case 31:
+ return "st";
+ case 2:
+ case 22:
+ return "nd";
+ case 3:
+ case 23:
+ return "rd";
+ default:
+ return "th";
+ }
+ };
+
+ return format ? format.replace(/(\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g,
+ function (m) {
+ if (m.charAt(0) === "\\") {
+ return m.replace("\\", "");
+ }
+ x.h = x.getHours;
+ switch (m) {
+ case "hh":
+ return p(x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12));
+ case "h":
+ return x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12);
+ case "HH":
+ return p(x.h());
+ case "H":
+ return x.h();
+ case "mm":
+ return p(x.getMinutes());
+ case "m":
+ return x.getMinutes();
+ case "ss":
+ return p(x.getSeconds());
+ case "s":
+ return x.getSeconds();
+ case "yyyy":
+ return p(x.getFullYear(), 4);
+ case "yy":
+ return p(x.getFullYear());
+ case "dddd":
+ return $C.dayNames[x.getDay()];
+ case "ddd":
+ return $C.abbreviatedDayNames[x.getDay()];
+ case "dd":
+ return p(x.getDate());
+ case "d":
+ return x.getDate();
+ case "MMMM":
+ return $C.monthNames[x.getMonth()];
+ case "MMM":
+ return $C.abbreviatedMonthNames[x.getMonth()];
+ case "MM":
+ return p((x.getMonth() + 1));
+ case "M":
+ return x.getMonth() + 1;
+ case "t":
+ return x.h() < 12 ? $C.amDesignator.substring(0, 1) : $C.pmDesignator.substring(0, 1);
+ case "tt":
+ return x.h() < 12 ? $C.amDesignator : $C.pmDesignator;
+ case "S":
+ return ord(x.getDate());
+ default:
+ return m;
+ }
+ }
+ ) : this._toString();
+ };
+}()); /**
+ * @version: 1.0 Alpha-1
+ * @author: Coolite Inc. http://www.coolite.com/
+ * @date: 2008-04-13
+ * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
+ * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
+ * @website: http://www.datejs.com/
+ */
+
+/**
+ **************************************************************
+ ** SugarPak - Domain Specific Language - Syntactical Sugar **
+ **************************************************************
+ */
+
+(function () {
+ var $D = Date, $P = $D.prototype, $C = $D.CultureInfo, $N = Number.prototype;
+
+ // private
+ $P._orient = +1;
+
+ // private
+ $P._nth = null;
+
+ // private
+ $P._is = false;
+
+ // private
+ $P._same = false;
+
+ // private
+ $P._isSecond = false;
+
+ // private
+ $N._dateElement = "day";
+
+ /**
+ * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+ <pre><code>
+ Date.today().next().friday();
+ Date.today().next().fri();
+ Date.today().next().march();
+ Date.today().next().mar();
+ Date.today().next().week();
+ </code></pre>
+ *
+ * @return {Date} date
+ */
+ $P.next = function () {
+ this._orient = +1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+ <pre><code>
+ Date.next().friday();
+ Date.next().fri();
+ Date.next().march();
+ Date.next().mar();
+ Date.next().week();
+ </code></pre>
+ *
+ * @return {Date} date
+ */
+ $D.next = function () {
+ return $D.today().next();
+ };
+
+ /**
+ * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+ <pre><code>
+ Date.today().last().friday();
+ Date.today().last().fri();
+ Date.today().last().march();
+ Date.today().last().mar();
+ Date.today().last().week();
+ </code></pre>
+ *
+ * @return {Date} date
+ */
+ $P.last = $P.prev = $P.previous = function () {
+ this._orient = -1;
+ return this;
+ };
+
+ /**
+ * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
+ * Example
+ <pre><code>
+ Date.last().friday();
+ Date.last().fri();
+ Date.previous().march();
+ Date.prev().mar();
+ Date.last().week();
+ </code></pre>
+ *
+ * @return {Date} date
+ */
+ $D.last = $D.prev = $D.previous = function () {
+ return $D.today().last();
+ };
+
+ /**
+ * Performs a equality check when followed by either a month name, day name or .weekday() function.
+ * Example
+ <pre><code>
+ Date.today().is().friday(); // true|false
+ Date.today().is().fri();
+ Date.today().is().march();
+ Date.today().is().mar();
+ </code></pre>
+ *
+ * @return {Boolean} true|false
+ */
+ $P.is = function () {
+ this._is = true;
+ return this;
+ };
+
+ /**
+ * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
+ * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
+ *
+ * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
+ *
+ * The following example demonstrates how to determine if two dates fall on the exact same day.
+ *
+ * Example
+ <pre><code>
+ var d1 = Date.today(); // today at 00:00
+ var d2 = new Date(); // exactly now.
+
+ // Do they occur on the same day?
+ d1.same().day(d2); // true
+
+ // Do they occur on the same hour?
+ d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
+
+ // What if it's the same day, but one year apart?
+ var nextYear = Date.today().add(1).year();
+
+ d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
+ </code></pre>
+ *
+ * Scenario: Determine if a given date occurs during some week period 2 months from now.
+ *
+ * Example
+ <pre><code>
+ var future = Date.today().add(2).months();
+ return someDate.same().week(future); // true|false;
+ </code></pre>
+ *
+ * @return {Boolean} true|false
+ */
+ $P.same = function () {
+ this._same = true;
+ this._isSecond = false;
+ return this;
+ };
+
+ /**
+ * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
+ * Example
+ <pre><code>
+ someDate.is().today(); // true|false
+ new Date().is().today(); // true
+ Date.today().is().today();// true
+ Date.today().add(-1).day().is().today(); // false
+ </code></pre>
+ *
+ * @return {Boolean} true|false
+ */
+ $P.today = function () {
+ return this.same().day();
+ };
+
+ /**
+ * Determines if the current date is a weekday. This function must be preceded by the .is() function.
+ * Example
+ <pre><code>
+ Date.today().is().weekday(); // true|false
+ </code></pre>
+ *
+ * @return {Boolean} true|false
+ */
+ $P.weekday = function () {
+ if (this._is) {
+ this._is = false;
+ return (!this.is().sat() && !this.is().sun());
+ }
+ return false;
+ };
+
+ /**
+ * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
+ * Example
+ <pre><code>
+ // Set time to 6:15pm with a String
+ Date.today().at("6:15pm");
+
+ // Set time to 6:15pm with a config object
+ Date.today().at({hour:18, minute:15});
+ </code></pre>
+ *
+ * @return {Date} date
+ */
+ $P.at = function (time) {
+ return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
+ };
+
+ /**
+ * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+ <pre><code>
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().fromNow();
+ (6).months().fromNow();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().fromNow();
+ </code></pre>
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.fromNow = $N.after = function (date) {
+ var c = {};
+ c[this._dateElement] = this;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ /**
+ * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
+ * Example
+ <pre><code>
+ // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
+ (3).days().ago();
+ (6).months().ago();
+
+ // Declared Number variables do not require parentheses.
+ var n = 6;
+ n.months().ago();
+ </code></pre>
+ *
+ * @return {Date} A new Date instance
+ */
+ $N.ago = $N.before = function (date) {
+ var c = {};
+ c[this._dateElement] = this * -1;
+ return ((!date) ? new Date() : date.clone()).add(c);
+ };
+
+ // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
+ // All culture-specific strings can be found in the CultureInfo files. See /trunk/src/globalization/.
+ var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
+ mx = ("january february march april may june july august september october november december").split(/\s/),
+ px = ("Millisecond Second Minute Hour Day Week Month Year").split(/\s/),
+ pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear").split(/\s/),
+ nth = ("final first second third fourth fifth").split(/\s/),
+ de;
+
+ /**
+ * Returns an object literal of all the date parts.
+ * Example
+ <pre><code>
+ var o = new Date().toObject();
+
+ // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
+
+ // The object properties can be referenced directly from the object.
+
+ alert(o.day); // alerts "13"
+ alert(o.year); // alerts "2008"
+ </code></pre>
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $P.toObject = function () {
+ var o = {};
+ for (var i = 0; i < px.length; i++) {
+ o[px[i].toLowerCase()] = this["get" + pxf[i]]();
+ }
+ return o;
+ };
+
+ /**
+ * Returns a date created from an object literal. Ignores the .week property if set in the config.
+ * Example
+ <pre><code>
+ var o = new Date().toObject();
+
+ return Date.fromObject(o); // will return the same date.
+
+ var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
+ Date.fromObject(o2);
+ </code></pre>
+ *
+ * @return {Date} An object literal representing the original date object.
+ */
+ $D.fromObject = function(config) {
+ config.week = null;
+ return Date.today().set(config);
+ };
+
+ // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
+ var df = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getDay() == n;
+ }
+ if (this._nth !== null) {
+ // If the .second() function was called earlier, remove the _orient
+ // from the date, and then continue.
+ // This is required because 'second' can be used in two different context.
+ //
+ // Example
+ //
+ // Date.today().add(1).second();
+ // Date.march().second().monday();
+ //
+ // Things get crazy with the following...
+ // Date.march().add(1).second().second().monday(); // but it works!!
+ //
+ if (this._isSecond) {
+ this.addSeconds(this._orient * -1);
+ }
+ // make sure we reset _isSecond
+ this._isSecond = false;
+
+ var ntemp = this._nth;
+ this._nth = null;
+ var temp = this.clone().moveToLastDayOfMonth();
+ this.moveToNthOccurrence(n, ntemp);
+ if (this > temp) {
+ throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
+ }
+ return this;
+ }
+ return this.moveToDayOfWeek(n, this._orient);
+ };
+ };
+
+ var sdf = function (n) {
+ return function () {
+ var t = $D.today(), shift = n - t.getDay();
+ if (n === 0 && $C.firstDayOfWeek === 1 && t.getDay() !== 0) {
+ shift = shift + 7;
+ }
+ return t.addDays(shift);
+ };
+ };
+
+ for (var i = 0; i < dx.length; i++) {
+ // Create constant static Day Name variables. Example: Date.MONDAY or Date.MON
+ $D[dx[i].toUpperCase()] = $D[dx[i].toUpperCase().substring(0, 3)] = i;
+
+ // Create Day Name functions. Example: Date.monday() or Date.mon()
+ $D[dx[i]] = $D[dx[i].substring(0, 3)] = sdf(i);
+
+ // Create Day Name instance functions. Example: Date.today().next().monday()
+ $P[dx[i]] = $P[dx[i].substring(0, 3)] = df(i);
+ }
+
+ // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
+ var mf = function (n) {
+ return function () {
+ if (this._is) {
+ this._is = false;
+ return this.getMonth() === n;
+ }
+ return this.moveToMonth(n, this._orient);
+ };
+ };
+
+ var smf = function (n) {
+ return function () {
+ return $D.today().set({ month: n, day: 1 });
+ };
+ };
+
+ for (var j = 0; j < mx.length; j++) {
+ // Create constant static Month Name variables. Example: Date.MARCH or Date.MAR
+ $D[mx[j].toUpperCase()] = $D[mx[j].toUpperCase().substring(0, 3)] = j;
+
+ // Create Month Name functions. Example: Date.march() or Date.mar()
+ $D[mx[j]] = $D[mx[j].substring(0, 3)] = smf(j);
+
+ // Create Month Name instance functions. Example: Date.today().next().march()
+ $P[mx[j]] = $P[mx[j].substring(0, 3)] = mf(j);
+ }
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ var ef = function (j) {
+ return function () {
+ // if the .second() function was called earlier, the _orient
+ // has alread been added. Just return this and reset _isSecond.
+ if (this._isSecond) {
+ this._isSecond = false;
+ return this;
+ }
+
+ if (this._same) {
+ this._same = this._is = false;
+ var o1 = this.toObject(),
+ o2 = (arguments[0] || new Date()).toObject(),
+ v = "",
+ k = j.toLowerCase();
+
+ for (var m = (px.length - 1); m > -1; m--) {
+ v = px[m].toLowerCase();
+ if (o1[v] != o2[v]) {
+ return false;
+ }
+ if (k == v) {
+ break;
+ }
+ }
+ return true;
+ }
+
+ if (j.substring(j.length - 1) != "s") {
+ j += "s";
+ }
+ return this["add" + j](this._orient);
+ };
+ };
+
+
+ var nf = function (n) {
+ return function () {
+ this._dateElement = n;
+ return this;
+ };
+ };
+
+ for (var k = 0; k < px.length; k++) {
+ de = px[k].toLowerCase();
+
+ // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
+ $P[de] = $P[de + "s"] = ef(px[k]);
+
+ // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
+ $N[de] = $N[de + "s"] = nf(de);
+ }
+
+ $P._ss = ef("Second");
+
+ var nthfn = function (n) {
+ return function (dayOfWeek) {
+ if (this._same) {
+ return this._ss(arguments[0]);
+ }
+ if (dayOfWeek || dayOfWeek === 0) {
+ return this.moveToNthOccurrence(dayOfWeek, n);
+ }
+ this._nth = n;
+
+ // if the operator is 'second' add the _orient, then deal with it later...
+ if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
+ this._isSecond = true;
+ return this.addSeconds(this._orient);
+ }
+ return this;
+ };
+ };
+
+ for (var l = 0; l < nth.length; l++) {
+ $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
+ }
+}());/**
+ * @version: 1.0 Alpha-1
+ * @author: Coolite Inc. http://www.coolite.com/
+ * @date: 2008-04-13
+ * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
+ * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
+ * @website: http://www.datejs.com/
+ */
+
+(function () {
+ Date.Parsing = {
+ Exception: function (s) {
+ this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
+ }
+ };
+
+ var $P = Date.Parsing;
+ var _ = $P.Operators = {
+ //
+ // Tokenizers
+ //
+ rtoken: function (r) { // regex token
+ return function (s) {
+ var mx = s.match(r);
+ if (mx) {
+ return ([ mx[0], s.substring(mx[0].length) ]);
+ } else {
+ throw new $P.Exception(s);
+ }
+ };
+ },
+ token: function (s) { // whitespace-eating token
+ return function (s) {
+ return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s);
+ // Removed .strip()
+ // return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s).strip();
+ };
+ },
+ stoken: function (s) { // string token
+ return _.rtoken(new RegExp("^" + s));
+ },
+
+ //
+ // Atomic Operators
+ //
+
+ until: function (p) {
+ return function (s) {
+ var qx = [], rx = null;
+ while (s.length) {
+ try {
+ rx = p.call(this, s);
+ } catch (e) {
+ qx.push(rx[0]);
+ s = rx[1];
+ continue;
+ }
+ break;
+ }
+ return [ qx, s ];
+ };
+ },
+ many: function (p) {
+ return function (s) {
+ var rx = [], r = null;
+ while (s.length) {
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ rx, s ];
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s ];
+ };
+ },
+
+ // generator operators -- see below
+ optional: function (p) {
+ return function (s) {
+ var r = null;
+ try {
+ r = p.call(this, s);
+ } catch (e) {
+ return [ null, s ];
+ }
+ return [ r[0], r[1] ];
+ };
+ },
+ not: function (p) {
+ return function (s) {
+ try {
+ p.call(this, s);
+ } catch (e) {
+ return [null, s];
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ ignore: function (p) {
+ return p ?
+ function (s) {
+ var r = null;
+ r = p.call(this, s);
+ return [null, r[1]];
+ } : null;
+ },
+ product: function () {
+ var px = arguments[0],
+ qx = Array.prototype.slice.call(arguments, 1), rx = [];
+ for (var i = 0 ; i < px.length ; i++) {
+ rx.push(_.each(px[i], qx));
+ }
+ return rx;
+ },
+ cache: function (rule) {
+ var cache = {}, r = null;
+ return function (s) {
+ try {
+ r = cache[s] = (cache[s] || rule.call(this, s));
+ } catch (e) {
+ r = cache[s] = e;
+ }
+ if (r instanceof $P.Exception) {
+ throw r;
+ } else {
+ return r;
+ }
+ };
+ },
+
+ // vector operators -- see below
+ any: function () {
+ var px = arguments;
+ return function (s) {
+ var r = null;
+ for (var i = 0; i < px.length; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ r = null;
+ }
+ if (r) {
+ return r;
+ }
+ }
+ throw new $P.Exception(s);
+ };
+ },
+ each: function () {
+ var px = arguments;
+ return function (s) {
+ var rx = [], r = null;
+ for (var i = 0; i < px.length ; i++) {
+ if (px[i] == null) {
+ continue;
+ }
+ try {
+ r = (px[i].call(this, s));
+ } catch (e) {
+ throw new $P.Exception(s);
+ }
+ rx.push(r[0]);
+ s = r[1];
+ }
+ return [ rx, s];
+ };
+ },
+ all: function () {
+ var px = arguments, _ = _;
+ return _.each(_.optional(px));
+ },
+
+ // delimited operators
+ sequence: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+
+ if (px.length == 1) {
+ return px[0];
+ }
+ return function (s) {
+ var r = null, q = null;
+ var rx = [];
+ for (var i = 0; i < px.length ; i++) {
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ break;
+ }
+ rx.push(r[0]);
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ q = null;
+ break;
+ }
+ s = q[1];
+ }
+ if (!r) {
+ throw new $P.Exception(s);
+ }
+ if (q) {
+ throw new $P.Exception(q[1]);
+ }
+ if (c) {
+ try {
+ r = c.call(this, r[1]);
+ } catch (ey) {
+ throw new $P.Exception(r[1]);
+ }
+ }
+ return [ rx, (r?r[1]:s) ];
+ };
+ },
+
+ //
+ // Composite Operators
+ //
+
+ between: function (d1, p, d2) {
+ d2 = d2 || d1;
+ var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
+ return function (s) {
+ var rx = _fn.call(this, s);
+ return [[rx[0][0], r[0][2]], rx[1]];
+ };
+ },
+ list: function (p, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return (p instanceof Array ?
+ _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
+ _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
+ },
+ set: function (px, d, c) {
+ d = d || _.rtoken(/^\s*/);
+ c = c || null;
+ return function (s) {
+ // r is the current match, best the current 'best' match
+ // which means it parsed the most amount of input
+ var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
+
+ // go through the rules in the given set
+ for (var i = 0; i < px.length ; i++) {
+
+ // last is a flag indicating whether this must be the last element
+ // if there is only 1 element, then it MUST be the last one
+ q = null;
+ p = null;
+ r = null;
+ last = (px.length == 1);
+
+ // first, we try simply to match the current pattern
+ // if not, try the next pattern
+ try {
+ r = px[i].call(this, s);
+ } catch (e) {
+ continue;
+ }
+
+ // since we are matching against a set of elements, the first
+ // thing to do is to add r[0] to matched elements
+ rx = [[r[0]], r[1]];
+
+ // if we matched and there is still input to parse and
+ // we don't already know this is the last element,
+ // we're going to next check for the delimiter ...
+ // if there's none, or if there's no input left to parse
+ // than this must be the last element after all ...
+ if (r[1].length > 0 && ! last) {
+ try {
+ q = d.call(this, r[1]);
+ } catch (ex) {
+ last = true;
+ }
+ } else {
+ last = true;
+ }
+
+ // if we parsed the delimiter and now there's no more input,
+ // that means we shouldn't have parsed the delimiter at all
+ // so don't update r and mark this as the last element ...
+ if (!last && q[1].length === 0) {
+ last = true;
+ }
+
+
+ // so, if this isn't the last element, we're going to see if
+ // we can get any more matches from the remaining (unmatched)
+ // elements ...
+ if (!last) {
+
+ // build a list of the remaining rules we can match against,
+ // i.e., all but the one we just matched against
+ var qx = [];
+ for (var j = 0; j < px.length ; j++) {
+ if (i != j) {
+ qx.push(px[j]);
+ }
+ }
+
+ // now invoke recursively set with the remaining input
+ // note that we don't include the closing delimiter ...
+ // we'll check for that ourselves at the end
+ p = _.set(qx, d).call(this, q[1]);
+
+ // if we got a non-empty set as a result ...
+ // (otw rx already contains everything we want to match)
+ if (p[0].length > 0) {
+ // update current result, which is stored in rx ...
+ // basically, pick up the remaining text from p[1]
+ // and concat the result from p[0] so that we don't
+ // get endless nesting ...
+ rx[0] = rx[0].concat(p[0]);
+ rx[1] = p[1];
+ }
+ }
+
+ // at this point, rx either contains the last matched element
+ // or the entire matched set that starts with this element.
+
+ // now we just check to see if this variation is better than
+ // our best so far, in terms of how much of the input is parsed
+ if (rx[1].length < best[1].length) {
+ best = rx;
+ }
+
+ // if we've parsed all the input, then we're finished
+ if (best[1].length === 0) {
+ break;
+ }
+ }
+
+ // so now we've either gone through all the patterns trying them
+ // as the initial match; or we found one that parsed the entire
+ // input string ...
+
+ // if best has no matches, just return empty set ...
+ if (best[0].length === 0) {
+ return best;
+ }
+
+ // if a closing delimiter is provided, then we have to check it also
+ if (c) {
+ // we try this even if there is no remaining input because the pattern
+ // may well be optional or match empty input ...
+ try {
+ q = c.call(this, best[1]);
+ } catch (ey) {
+ throw new $P.Exception(best[1]);
+ }
+
+ // it parsed ... be sure to update the best match remaining input
+ best[1] = q[1];
+ }
+
+ // if we're here, either there was no closing delimiter or we parsed it
+ // so now we have the best match; just return it!
+ return best;
+ };
+ },
+ forward: function (gr, fname) {
+ return function (s) {
+ return gr[fname].call(this, s);
+ };
+ },
+
+ //
+ // Translation Operators
+ //
+ replace: function (rule, repl) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [repl, r[1]];
+ };
+ },
+ process: function (rule, fn) {
+ return function (s) {
+ var r = rule.call(this, s);
+ return [fn.call(this, r[0]), r[1]];
+ };
+ },
+ min: function (min, rule) {
+ return function (s) {
+ var rx = rule.call(this, s);
+ if (rx[0].length < min) {
+ throw new $P.Exception(s);
+ }
+ return rx;
+ };
+ }
+ };
+
+
+ // Generator Operators And Vector Operators
+
+ // Generators are operators that have a signature of F(R) => R,
+ // taking a given rule and returning another rule, such as
+ // ignore, which parses a given rule and throws away the result.
+
+ // Vector operators are those that have a signature of F(R1,R2,...) => R,
+ // take a list of rules and returning a new rule, such as each.
+
+ // Generator operators are converted (via the following _generator
+ // function) into functions that can also take a list or array of rules
+ // and return an array of new rules as though the function had been
+ // called on each rule in turn (which is what actually happens).
+
+ // This allows generators to be used with vector operators more easily.
+ // Example:
+ // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
+
+ // This also turns generators into vector operators, which allows
+ // constructs like:
+ // not(cache(foo, bar))
+
+ var _generator = function (op) {
+ return function () {
+ var args = null, rx = [];
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ } else if (arguments[0] instanceof Array) {
+ args = arguments[0];
+ }
+ if (args) {
+ for (var i = 0, px = args.shift() ; i < px.length ; i++) {
+ args.unshift(px[i]);
+ rx.push(op.apply(null, args));
+ args.shift();
+ return rx;
+ }
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var gx = "optional not ignore cache".split(/\s/);
+
+ for (var i = 0 ; i < gx.length ; i++) {
+ _[gx[i]] = _generator(_[gx[i]]);
+ }
+
+ var _vector = function (op) {
+ return function () {
+ if (arguments[0] instanceof Array) {
+ return op.apply(null, arguments[0]);
+ } else {
+ return op.apply(null, arguments);
+ }
+ };
+ };
+
+ var vx = "each any all".split(/\s/);
+
+ for (var j = 0 ; j < vx.length ; j++) {
+ _[vx[j]] = _vector(_[vx[j]]);
+ }
+
+}());
+
+(function () {
+ var $D = Date, $P = $D.prototype, $C = $D.CultureInfo;
+
+ var flattenAndCompact = function (ax) {
+ var rx = [];
+ for (var i = 0; i < ax.length; i++) {
+ if (ax[i] instanceof Array) {
+ rx = rx.concat(flattenAndCompact(ax[i]));
+ } else {
+ if (ax[i]) {
+ rx.push(ax[i]);
+ }
+ }
+ }
+ return rx;
+ };
+
+ $D.Grammar = {};
+
+ $D.Translator = {
+ hour: function (s) {
+ return function () {
+ this.hour = Number(s);
+ };
+ },
+ minute: function (s) {
+ return function () {
+ this.minute = Number(s);
+ };
+ },
+ second: function (s) {
+ return function () {
+ this.second = Number(s);
+ };
+ },
+ meridian: function (s) {
+ return function () {
+ this.meridian = s.slice(0, 1).toLowerCase();
+ };
+ },
+ timezone: function (s) {
+ return function () {
+ var n = s.replace(/[^\d\+\-]/g, "");
+ if (n.length) {
+ this.timezoneOffset = Number(n);
+ } else {
+ this.timezone = s.toLowerCase();
+ }
+ };
+ },
+ day: function (x) {
+ var s = x[0];
+ return function () {
+ this.day = Number(s.match(/\d+/)[0]);
+ };
+ },
+ month: function (s) {
+ return function () {
+ this.month = (s.length == 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
+ };
+ },
+ year: function (s) {
+ return function () {
+ var n = Number(s);
+ this.year = ((s.length > 2) ? n :
+ (n + (((n + 2000) < $C.twoDigitYearMax) ? 2000 : 1900)));
+ };
+ },
+ rday: function (s) {
+ return function () {
+ switch (s) {
+ case "yesterday":
+ this.days = -1;
+ break;
+ case "tomorrow":
+ this.days = 1;
+ break;
+ case "today":
+ this.days = 0;
+ break;
+ case "now":
+ this.days = 0;
+ this.now = true;
+ break;
+ }
+ };
+ },
+ finishExact: function (x) {
+ x = (x instanceof Array) ? x : [ x ];
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (x[i]) {
+ x[i].call(this);
+ }
+ }
+
+ var now = new Date();
+
+ if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
+ this.day = now.getDate();
+ }
+
+ if (!this.year) {
+ this.year = now.getFullYear();
+ }
+
+ if (!this.month && this.month !== 0) {
+ this.month = now.getMonth();
+ }
+
+ if (!this.day) {
+ this.day = 1;
+ }
+
+ if (!this.hour) {
+ this.hour = 0;
+ }
+
+ if (!this.minute) {
+ this.minute = 0;
+ }
+
+ if (!this.second) {
+ this.second = 0;
+ }
+
+ if (this.meridian && this.hour) {
+ if (this.meridian == "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian == "a" && this.hour == 12) {
+ this.hour = 0;
+ }
+ }
+
+ if (this.day > $D.getDaysInMonth(this.year, this.month)) {
+ throw new RangeError(this.day + " is not a valid value for days.");
+ }
+
+ var r = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second);
+
+ if (this.timezone) {
+ r.set({ timezone: this.timezone });
+ } else if (this.timezoneOffset) {
+ r.set({ timezoneOffset: this.timezoneOffset });
+ }
+
+ return r;
+ },
+ finish: function (x) {
+ x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
+
+ if (x.length === 0) {
+ return null;
+ }
+
+ for (var i = 0 ; i < x.length ; i++) {
+ if (typeof x[i] == "function") {
+ x[i].call(this);
+ }
+ }
+
+ var today = $D.today();
+
+ if (this.now && !this.unit && !this.operator) {
+ return new Date();
+ } else if (this.now) {
+ today = new Date();
+ }
+
+ var expression = !!(this.days && this.days !== null || this.orient || this.operator);
+
+ var gap, mod, orient;
+ orient = ((this.orient == "past" || this.operator == "subtract") ? -1 : 1);
+
+ if(!this.now && "hour minute second".indexOf(this.unit) != -1) {
+ today.setTimeToNow();
+ }
+
+ if (this.month || this.month === 0) {
+ if ("year day hour minute second".indexOf(this.unit) != -1) {
+ this.value = this.month + 1;
+ this.month = null;
+ expression = true;
+ }
+ }
+
+ if (!expression && this.weekday && !this.day && !this.days) {
+ var temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (!this.month) {
+ this.month = temp.getMonth();
+ }
+ this.year = temp.getFullYear();
+ }
+
+ if (expression && this.weekday && this.unit != "month") {
+ this.unit = "day";
+ gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
+ mod = 7;
+ this.days = gap ? ((gap + (orient * mod)) % mod) : (orient * mod);
+ }
+
+ if (this.month && this.unit == "day" && this.operator) {
+ this.value = (this.month + 1);
+ this.month = null;
+ }
+
+ if (this.value != null && this.month != null && this.year != null) {
+ this.day = this.value * 1;
+ }
+
+ if (this.month && !this.day && this.value) {
+ today.set({ day: this.value * 1 });
+ if (!expression) {
+ this.day = this.value * 1;
+ }
+ }
+
+ if (!this.month && this.value && this.unit == "month" && !this.now) {
+ this.month = this.value;
+ expression = true;
+ }
+
+ if (expression && (this.month || this.month === 0) && this.unit != "year") {
+ this.unit = "month";
+ gap = (this.month - today.getMonth());
+ mod = 12;
+ this.months = gap ? ((gap + (orient * mod)) % mod) : (orient * mod);
+ this.month = null;
+ }
+
+ if (!this.unit) {
+ this.unit = "day";
+ }
+
+ if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
+ this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator == "add") ? 1 : -1) + (this.value||0) * orient;
+ } else if (this[this.unit + "s"] == null || this.operator != null) {
+ if (!this.value) {
+ this.value = 1;
+ }
+ this[this.unit + "s"] = this.value * orient;
+ }
+
+ if (this.meridian && this.hour) {
+ if (this.meridian == "p" && this.hour < 12) {
+ this.hour = this.hour + 12;
+ } else if (this.meridian == "a" && this.hour == 12) {
+ this.hour = 0;
+ }
+ }
+
+ if (this.weekday && !this.day && !this.days) {
+ var temp = Date[this.weekday]();
+ this.day = temp.getDate();
+ if (temp.getMonth() !== today.getMonth()) {
+ this.month = temp.getMonth();
+ }
+ }
+
+ if ((this.month || this.month === 0) && !this.day) {
+ this.day = 1;
+ }
+
+ if (!this.orient && !this.operator && this.unit == "week" && this.value && !this.day && !this.month) {
+ return Date.today().setWeek(this.value);
+ }
+
+ if (expression && this.timezone && this.day && this.days) {
+ this.day = this.days;
+ }
+
+ return (expression) ? today.add(this) : today.set(this);
+ }
+ };
+
+ var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
+
+ g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
+ g.timePartDelimiter = _.stoken(":");
+ g.whiteSpace = _.rtoken(/^\s*/);
+ g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
+
+ var _C = {};
+ g.ctoken = function (keys) {
+ var fn = _C[keys];
+ if (! fn) {
+ var c = $C.regexPatterns;
+ var kx = keys.split(/\s+/), px = [];
+ for (var i = 0; i < kx.length ; i++) {
+ px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
+ }
+ fn = _C[keys] = _.any.apply(null, px);
+ }
+ return fn;
+ };
+ g.ctoken2 = function (key) {
+ return _.rtoken($C.regexPatterns[key]);
+ };
+
+ // hour, minute, second, meridian, timezone
+ g.h = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/), t.hour));
+ g.hh = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/), t.hour));
+ g.H = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/), t.hour));
+ g.HH = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/), t.hour));
+ g.m = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.minute));
+ g.mm = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.minute));
+ g.s = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.second));
+ g.ss = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.second));
+ g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
+
+ // _.min(1, _.set([ g.H, g.m, g.s ], g._t));
+ g.t = _.cache(_.process(g.ctoken2("shortMeridian"), t.meridian));
+ g.tt = _.cache(_.process(g.ctoken2("longMeridian"), t.meridian));
+ g.z = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone));
+ g.zz = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone));
+
+ g.zzz = _.cache(_.process(g.ctoken2("timezone"), t.timezone));
+ g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
+ g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
+
+ // days, months, years
+ g.d = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/),
+ _.optional(g.ctoken2("ordinalSuffix"))), t.day));
+ g.dd = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/),
+ _.optional(g.ctoken2("ordinalSuffix"))), t.day));
+ g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
+ function (s) {
+ return function () {
+ this.weekday = s;
+ };
+ }
+ ));
+ g.M = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/), t.month));
+ g.MM = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/), t.month));
+ g.MMM = g.MMMM = _.cache(_.process(
+ g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
+ g.y = _.cache(_.process(_.rtoken(/^(\d\d?)/), t.year));
+ g.yy = _.cache(_.process(_.rtoken(/^(\d\d)/), t.year));
+ g.yyy = _.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/), t.year));
+ g.yyyy = _.cache(_.process(_.rtoken(/^(\d\d\d\d)/), t.year));
+
+ // rolling these up into general purpose rules
+ _fn = function () {
+ return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
+ };
+
+ g.day = _fn(g.d, g.dd);
+ g.month = _fn(g.M, g.MMM);
+ g.year = _fn(g.yyyy, g.yy);
+
+ // relative date / time expressions
+ g.orientation = _.process(g.ctoken("past future"),
+ function (s) {
+ return function () {
+ this.orient = s;
+ };
+ }
+ );
+ g.operator = _.process(g.ctoken("add subtract"),
+ function (s) {
+ return function () {
+ this.operator = s;
+ };
+ }
+ );
+ g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
+ g.unit = _.process(g.ctoken("second minute hour day week month year"),
+ function (s) {
+ return function () {
+ this.unit = s;
+ };
+ }
+ );
+ g.value = _.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/),
+ function (s) {
+ return function () {
+ this.value = s.replace(/\D/g, "");
+ };
+ }
+ );
+ g.expression = _.set([ g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
+
+ // pre-loaded rules for different date part order preferences
+ _fn = function () {
+ return _.set(arguments, g.datePartDelimiter);
+ };
+ g.mdy = _fn(g.ddd, g.month, g.day, g.year);
+ g.ymd = _fn(g.ddd, g.year, g.month, g.day);
+ g.dmy = _fn(g.ddd, g.day, g.month, g.year);
+ g.date = function (s) {
+ return ((g[$C.dateElementOrder] || g.mdy).call(this, s));
+ };
+
+ // parsing date format specifiers - ex: "h:m:s tt"
+ // this little guy will generate a custom parser based
+ // on the format string, ex: g.format("h:m:s tt")
+ g.format = _.process(_.many(
+ _.any(
+ // translate format specifiers into grammar rules
+ _.process(
+ _.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
+ function (fmt) {
+ if (g[fmt]) {
+ return g[fmt];
+ } else {
+ throw $D.Parsing.Exception(fmt);
+ }
+ }
+ ),
+ // translate separator tokens into token rules
+ _.process(
+ _.rtoken(/^[^dMyhHmstz]+/), // all legal separators
+ function (s) {
+ return _.ignore(_.stoken(s));
+ }
+ )
+ )),
+ // construct the parser ...
+ function (rules) {
+ return _.process(_.each.apply(null, rules), t.finishExact);
+ }
+ );
+
+ var _F = {
+ //"M/d/yyyy": function (s) {
+ // var m = s.match(/^([0-2]\d|3[0-1]|\d)\/(1[0-2]|0\d|\d)\/(\d\d\d\d)/);
+ // if (m!=null) {
+ // var r = [ t.month.call(this,m[1]), t.day.call(this,m[2]), t.year.call(this,m[3]) ];
+ // r = t.finishExact.call(this,r);
+ // return [ r, "" ];
+ // } else {
+ // throw new Date.Parsing.Exception(s);
+ // }
+ //}
+ //"M/d/yyyy": function (s) { return [ new Date(Date._parse(s)), ""]; }
+ };
+ var _get = function (f) {
+ return _F[f] = (_F[f] || g.format(f)[0]);
+ };
+
+ g.formats = function (fx) {
+ if (fx instanceof Array) {
+ var rx = [];
+ for (var i = 0 ; i < fx.length ; i++) {
+ rx.push(_get(fx[i]));
+ }
+ return _.any.apply(null, rx);
+ } else {
+ return _get(fx);
+ }
+ };
+
+ // check for these formats first
+ g._formats = g.formats([
+ "\"yyyy-MM-ddTHH:mm:ssZ\"",
+ "yyyy-MM-ddTHH:mm:ssZ",
+ "yyyy-MM-ddTHH:mm:ssz",
+ "yyyy-MM-ddTHH:mm:ss",
+ "yyyy-MM-ddTHH:mmZ",
+ "yyyy-MM-ddTHH:mmz",
+ "yyyy-MM-ddTHH:mm",
+ "ddd, MMM dd, yyyy H:mm:ss tt",
+ "ddd MMM d yyyy HH:mm:ss zzz",
+ "MMddyyyy",
+ "ddMMyyyy",
+ "Mddyyyy",
+ "ddMyyyy",
+ "Mdyyyy",
+ "dMyyyy",
+ "yyyy",
+ "Mdyy",
+ "dMyy",
+ "d"
+ ]);
+
+ // starting rule for general purpose grammar
+ g._start = _.process(_.set([ g.date, g.time, g.expression ],
+ g.generalDelimiter, g.whiteSpace), t.finish);
+
+ // real starting rule: tries selected formats first,
+ // then general purpose rule
+ g.start = function (s) {
+ try {
+ var r = g._formats.call({}, s);
+ if (r[1].length === 0) {
+ return r;
+ }
+ } catch (e) {}
+ return g._start.call({}, s);
+ };
+
+ $D._parse = $D.parse;
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
+ *
+ * Example
+ <pre><code>
+ ///////////
+ // Dates //
+ ///////////
+
+ // 15-Oct-2004
+ var d1 = Date.parse("10/15/2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15");
+
+ //Fri Oct 15, 2004
+ var d1 = Date.parse("Fri Oct 15, 2004");
+
+ ///////////
+ // Times //
+ ///////////
+
+ // Today at 10 PM.
+ var d1 = Date.parse("10 PM");
+
+ // Today at 10:30 PM.
+ var d1 = Date.parse("10:30 P.M.");
+
+ // Today at 6 AM.
+ var d1 = Date.parse("06am");
+
+ /////////////////////
+ // Dates and Times //
+ /////////////////////
+
+ // 8-July-2004 @ 10:30 PM
+ var d1 = Date.parse("July 8th, 2004, 10:30 PM");
+
+ // 1-July-2004 @ 10:30 PM
+ var d1 = Date.parse("2004-07-01T22:30:00");
+
+ ////////////////////
+ // Relative Dates //
+ ////////////////////
+
+ // Returns today's date. The string "today" is culture specific.
+ var d1 = Date.parse("today");
+
+ // Returns yesterday's date. The string "yesterday" is culture specific.
+ var d1 = Date.parse("yesterday");
+
+ // Returns the date of the next thursday.
+ var d1 = Date.parse("Next thursday");
+
+ // Returns the date of the most previous monday.
+ var d1 = Date.parse("last monday");
+
+ // Returns today's day + one year.
+ var d1 = Date.parse("next year");
+
+ ///////////////
+ // Date Math //
+ ///////////////
+
+ // Today + 2 days
+ var d1 = Date.parse("t+2");
+
+ // Today + 2 days
+ var d1 = Date.parse("today + 2 days");
+
+ // Today + 3 months
+ var d1 = Date.parse("t+3m");
+
+ // Today - 1 year
+ var d1 = Date.parse("today - 1 year");
+
+ // Today - 1 year
+ var d1 = Date.parse("t-1y");
+
+
+ /////////////////////////////
+ // Partial Dates and Times //
+ /////////////////////////////
+
+ // July 15th of this year.
+ var d1 = Date.parse("July 15");
+
+ // 15th day of current day and year.
+ var d1 = Date.parse("15");
+
+ // July 1st of current year at 10pm.
+ var d1 = Date.parse("7/1 10pm");
+ </code></pre>
+ *
+ * @param {String} The string value to convert into a Date object [Required]
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parse = function (s) {
+ var r = null;
+ if (!s) {
+ return null;
+ }
+ if (s instanceof Date) {
+ return s;
+ }
+ try {
+ r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
+ } catch (e) {
+ return null;
+ }
+ return ((r[1].length === 0) ? r[0] : null);
+ };
+
+ $D.getParseFunction = function (fx) {
+ var fn = $D.Grammar.formats(fx);
+ return function (s) {
+ var r = null;
+ try {
+ r = fn.call({}, s);
+ } catch (e) {
+ return null;
+ }
+ return ((r[1].length === 0) ? r[0] : null);
+ };
+ };
+
+ /**
+ * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
+ * The format of the string value must match one of the supplied formats exactly.
+ *
+ * Example
+ <pre><code>
+ // 15-Oct-2004
+ var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
+
+ // 15-Oct-2004
+ var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
+
+ // Multiple formats
+ var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
+ </code></pre>
+ *
+ * @param {String} The string value to convert into a Date object [Required].
+ * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
+ * @return {Date} A Date object or null if the string cannot be converted into a Date.
+ */
+ $D.parseExact = function (s, fx) {
+ return $D.getParseFunction(fx)(s);
+ };
+}());
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "de-DE",
+ englishName: "German (Germany)",
+ nativeName: "Deutsch (Deutschland)",
+
+ /* Day Name Strings */
+ dayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
+ abbreviatedDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
+ shortestDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "D", "M", "D", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "dddd, d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^märz/i,
+ apr: /^apr(il)?/i,
+ may: /^mai/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dez(ember)?/i,
+
+ sun: /^sonntag/i,
+ mon: /^montag/i,
+ tue: /^dienstag/i,
+ wed: /^mittwoch/i,
+ thu: /^donnerstag/i,
+ fri: /^freitag/i,
+ sat: /^samstag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "el-GR",
+ englishName: "Greek (Greece)",
+ nativeName: "ελληνικά (Ελλάδα)",
+
+ /* Day Name Strings */
+ dayNames: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο"],
+ abbreviatedDayNames: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ"],
+ shortestDayNames: ["Κυ", "Δε", "Τρ", "Τε", "Πε", "Πα", "Σά"],
+ firstLetterDayNames: ["Κ", "Δ", "Τ", "Τ", "Π", "Π", "Σ"],
+
+ /* Month Name Strings */
+ monthNames: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"],
+ abbreviatedMonthNames: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαϊ", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"],
+
+ /* AM/PM Designators */
+ amDesignator: "πμ",
+ pmDesignator: "μμ",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d/M/yyyy",
+ longDate: "dddd, d MMMM yyyy",
+ shortTime: "h:mm tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "dddd, d MMMM yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ιαν(ουάριος)?/i,
+ feb: /^φεβ(ρουάριος)?/i,
+ mar: /^μάρτιος/i,
+ apr: /^απρ(ίλιος)?/i,
+ may: /^μάιος/i,
+ jun: /^ιούνιος/i,
+ jul: /^ιούλιος/i,
+ aug: /^αύγουστος/i,
+ sep: /^σεπ(τέμβριος)?/i,
+ oct: /^οκτ(ώβριος)?/i,
+ nov: /^νοέμβριος/i,
+ dec: /^δεκ(έμβριος)?/i,
+
+ sun: /^κυ(ρ(ιακή)?)?/i,
+ mon: /^δε(υ(τέρα)?)?/i,
+ tue: /^τρ(ι(τη)?)?/i,
+ wed: /^τε(τ(άρτη)?)?/i,
+ thu: /^πε(μ(πτη)?)?/i,
+ fri: /^πα(ρ(ασκευή)?)?/i,
+ sat: /^σά(β(βατο)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Event.observe(window, 'load', function() {
+ var nodeCount = kronolithNodes.length;
+ for (var n = 0; n < nodeCount; n++) {
+ var j = kronolithNodes[n];
+ $(j).update(kronolith[j]);
+ if (typeof Horde_ToolTips != 'undefined') {
+ // Need a closure here to ensure we preserve the value of j during
+ // each loop iteration.
+ (function() {
+ var jx = j;
+ Horde_ToolTips.attachBehavior(jx);
+ })();
+ }
+ }
+ Event.observe(window, 'unload', Horde_ToolTips.out.bind(Horde_ToolTips));
+});
\ No newline at end of file
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "en-US",
+ englishName: "English (United States)",
+ nativeName: "English (United States)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "mdy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "M/d/yyyy",
+ longDate: "dddd, MMMM dd, yyyy",
+ shortTime: "h:mm tt",
+ longTime: "h:mm:ss tt",
+ fullDateTime: "dddd, MMMM dd, yyyy h:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "es-ES",
+ englishName: "Spanish (Spain)",
+ nativeName: "español (España)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
+ shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
+ abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ene(ro)?/i,
+ feb: /^feb(rero)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^may(o)?/i,
+ jun: /^jun(io)?/i,
+ jul: /^jul(io)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^sep(tiembre)?/i,
+ oct: /^oct(ubre)?/i,
+ nov: /^nov(iembre)?/i,
+ dec: /^dic(iembre)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(n(es)?)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mi(é(rcoles)?)?/i,
+ thu: /^ju(e(ves)?)?/i,
+ fri: /^vi(e(rnes)?)?/i,
+ sat: /^sá(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "et-EE",
+ englishName: "Estonian (Estonia)",
+ nativeName: "eesti (Eesti)",
+
+ /* Day Name Strings */
+ dayNames: ["pühapäev", "esmaspäev", "teisipäev", "kolmapäev", "neljapäev", "reede", "laupäev"],
+ abbreviatedDayNames: ["P", "E", "T", "K", "N", "R", "L"],
+ shortestDayNames: ["P", "E", "T", "K", "N", "R", "L"],
+ firstLetterDayNames: ["P", "E", "T", "K", "N", "R", "L"],
+
+ /* Month Name Strings */
+ monthNames: ["jaanuar", "veebruar", "märts", "aprill", "mai", "juuni", "juuli", "august", "september", "oktoober", "november", "detsember"],
+ abbreviatedMonthNames: ["jaan", "veebr", "märts", "apr", "mai", "juuni", "juuli", "aug", "sept", "okt", "nov", "dets"],
+
+ /* AM/PM Designators */
+ amDesignator: "EL",
+ pmDesignator: "PL",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.MM.yyyy",
+ longDate: "d. MMMM yyyy'. a.'",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy'. a.' H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy'. a.'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jaan(uar)?/i,
+ feb: /^veebr(uar)?/i,
+ mar: /^märts/i,
+ apr: /^apr(ill)?/i,
+ may: /^mai/i,
+ jun: /^juuni/i,
+ jul: /^juuli/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(oober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dets(ember)?/i,
+
+ sun: /^pühapäev/i,
+ mon: /^esmaspäev/i,
+ tue: /^teisipäev/i,
+ wed: /^kolmapäev/i,
+ thu: /^neljapäev/i,
+ fri: /^reede/i,
+ sat: /^laupäev/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "eu-ES",
+ englishName: "Basque (Basque)",
+ nativeName: "euskara (euskara)",
+
+ /* Day Name Strings */
+ dayNames: ["igandea", "astelehena", "asteartea", "asteazkena", "osteguna", "ostirala", "larunbata"],
+ abbreviatedDayNames: ["ig.", "al.", "as.", "az.", "og.", "or.", "lr."],
+ shortestDayNames: ["ig", "al", "as", "az", "og", "or", "lr"],
+ firstLetterDayNames: ["i", "a", "a", "a", "o", "o", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["urtarrila", "otsaila", "martxoa", "apirila", "maiatza", "ekaina", "uztaila", "abuztua", "iraila", "urria", "azaroa", "abendua"],
+ abbreviatedMonthNames: ["urt.", "ots.", "mar.", "api.", "mai.", "eka.", "uzt.", "abu.", "ira.", "urr.", "aza.", "abe."],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/MM/dd",
+ longDate: "dddd, yyyy.'eko' MMMM'k 'd",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, yyyy.'eko' MMMM'k 'd HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "yyyy.'eko' MMMM"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^urt(.(arrila)?)?/i,
+ feb: /^ots(.(aila)?)?/i,
+ mar: /^mar(.(txoa)?)?/i,
+ apr: /^api(.(rila)?)?/i,
+ may: /^mai(.(atza)?)?/i,
+ jun: /^eka(.(ina)?)?/i,
+ jul: /^uzt(.(aila)?)?/i,
+ aug: /^abu(.(ztua)?)?/i,
+ sep: /^ira(.(ila)?)?/i,
+ oct: /^urr(.(ia)?)?/i,
+ nov: /^aza(.(roa)?)?/i,
+ dec: /^abe(.(ndua)?)?/i,
+
+ sun: /^ig((.(andea)?)?)?/i,
+ mon: /^al((.(telehena)?)?)?/i,
+ tue: /^as((.(teartea)?)?)?/i,
+ wed: /^az((.(teazkena)?)?)?/i,
+ thu: /^og((.(teguna)?)?)?/i,
+ fri: /^or((.(tirala)?)?)?/i,
+ sat: /^lr((.(runbata)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+/**
+ * @version: 1.0 Alpha-1
+ * @author: Coolite Inc. http://www.coolite.com/
+ * @date: 2008-04-13
+ * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
+ * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
+ * @website: http://www.datejs.com/
+ */
+
+(function () {
+ var $D = Date,
+ $P = $D.prototype,
+ $C = $D.CultureInfo,
+ $f = [],
+ p = function (s, l) {
+ if (!l) {
+ l = 2;
+ }
+ return ("000" + s).slice(l * -1);
+ };
+
+ /**
+ * Converts a PHP format string to Java/.NET format string.
+ * A PHP format string can be used with .$format or .format.
+ * A Java/.NET format string can be used with .toString().
+ * The .parseExact function will only accept a Java/.NET format string
+ *
+ * Example
+ <pre>
+ var f1 = "%m/%d/%y"
+ var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
+
+ new Date().format(f1); // "04/13/08"
+ new Date().$format(f1); // "04/13/08"
+ new Date().toString(f2); // "04/13/08"
+
+ var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
+ </pre>
+ * @param {String} A PHP format string consisting of one or more format spcifiers.
+ * @return {String} The PHP format converted to a Java/.NET format string.
+ */
+ $D.normalizeFormat = function (format) {
+ $f = [];
+ var t = new Date().$format(format);
+ return $f.join("");
+ };
+
+ /**
+ * Format a local Unix timestamp according to locale settings
+ *
+ * Example
+ <pre>
+ Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
+ Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
+ </pre>
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Number} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strftime = function (format, time) {
+ return new Date(time * 1000).$format(format);
+ };
+
+ /**
+ * Parse any textual datetime description into a Unix timestamp.
+ * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
+ *
+ * Example
+ <pre>
+ Date.strtotime("04/13/08"); // 1208044800
+ Date.strtotime("1970-01-01T00:00:00Z"); // 0
+ </pre>
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @param {Object} A string or date object.
+ * @return {String} A string representation of the current Date object.
+ */
+ $D.strtotime = function (time) {
+ var d = $D.parse(time);
+ d.addMinutes(d.getTimezoneOffset() * -1);
+ return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
+ };
+
+ /**
+ * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
+ *
+ * The following descriptions are from http://www.php.net/strftime and http://www.php.net/manual/en/function.date.php.
+ * Copyright © 2001-2008 The PHP Group
+ *
+ * Format Specifiers
+ <pre>
+ Format Description Example
+ ------ --------------------------------------------------------------------------- -----------------------
+ %a abbreviated weekday name according to the current localed "Mon" through "Sun"
+ %A full weekday name according to the current locale "Sunday" through "Saturday"
+ %b abbreviated month name according to the current locale "Jan" through "Dec"
+ %B full month name according to the current locale "January" through "December"
+ %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
+ %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
+ %d day of the month as a decimal number "01" to "31"
+ %D same as %m/%d/%y "04/13/08"
+ %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
+ %g like %G, but without the century "08"
+ %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
+ This has the same format and value as %Y, except that if the ISO week number
+ belongs to the previous or next year, that year is used instead.
+ %h same as %b "Jan" through "Dec"
+ %H hour as a decimal number using a 24-hour clock "00" to "23"
+ %I hour as a decimal number using a 12-hour clock "01" to "12"
+ %j day of the year as a decimal number "001" to "366"
+ %m month as a decimal number "01" to "12"
+ %M minute as a decimal number "00" to "59"
+ %n newline character "\n"
+ %p either "am" or "pm" according to the given time value, or the "am" or "pm"
+ corresponding strings for the current locale
+ %r time in a.m. and p.m. notation "8:44 PM"
+ %R time in 24 hour notation "20:44"
+ %S second as a decimal number "00" to "59"
+ %t tab character "\t"
+ %T current time, equal to %H:%M:%S "12:49:11"
+ %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
+ %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
+ first Sunday as the first day of the first week
+ %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
+ range 01 to 53, where week 1 is the first week that has at least 4 days
+ in the current year, and with Monday as the first day of the week.
+ (Use %G or %g for the year component that corresponds to the week number
+ for the specified timestamp.)
+ %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
+ first Monday as the first day of the first week
+ %w day of the week as a decimal, Sunday being "0" "0" to "6"
+ %x preferred date representation for the current locale without the time "4/13/2008"
+ %X preferred time representation for the current locale without the date "12:53:05"
+ %y year as a decimal number without a century "00" "99"
+ %Y year as a decimal number including the century "2008"
+ %Z time zone or name or abbreviation "UTC", "EST", "PST"
+ %z same as %Z
+ %% a literal "%" character "%"
+
+ d Day of the month, 2 digits with leading zeros "01" to "31"
+ D A textual representation of a day, three letters "Mon" through "Sun"
+ j Day of the month without leading zeros "1" to "31"
+ l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
+ N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
+ S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
+ w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
+ z The day of the year (starting from "0") "0" through "365"
+ W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
+ F A full textual representation of a month, such as January or March "January" through "December"
+ m Numeric representation of a month, with leading zeros "01" through "12"
+ M A short textual representation of a month, three letters "Jan" through "Dec"
+ n Numeric representation of a month, without leading zeros "1" through "12"
+ t Number of days in the given month "28" through "31"
+ L Whether it's a leap year "1" if it is a leap year, "0" otherwise
+ o ISO-8601 year number. This has the same value as Y, except that if the "2008"
+ ISO week number (W) belongs to the previous or next year, that year
+ is used instead.
+ Y A full numeric representation of a year, 4 digits "2008"
+ y A two digit representation of a year "08"
+ a Lowercase Ante meridiem and Post meridiem "am" or "pm"
+ A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
+ B Swatch Internet time "000" through "999"
+ g 12-hour format of an hour without leading zeros "1" through "12"
+ G 24-hour format of an hour without leading zeros "0" through "23"
+ h 12-hour format of an hour with leading zeros "01" through "12"
+ H 24-hour format of an hour with leading zeros "00" through "23"
+ i Minutes with leading zeros "00" to "59"
+ s Seconds, with leading zeros "00" through "59"
+ u Milliseconds "54321"
+ e Timezone identifier "UTC", "EST", "PST"
+ I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
+ O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
+ P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
+ T Timezone abbreviation "UTC", "EST", "PST"
+ Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
+ always negative, and for those east of UTC is always positive.
+ c ISO 8601 date "2004-02-12T15:19:21+00:00"
+ r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
+ U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
+ </pre>
+ * @param {String} A format string consisting of one or more format spcifiers [Optional].
+ * @return {String} A string representation of the current Date object.
+ */
+ $P.$format = function (format) {
+ var x = this,
+ y,
+ t = function (v) {
+ $f.push(v);
+ return x.toString(v);
+ };
+
+ return format ? format.replace(/(%|\\)?.|%%/g,
+ function (m) {
+ if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
+ return m.replace("\\", "").replace("%%", "%");
+ }
+ switch (m) {
+ case "d":
+ case "%d":
+ return t("dd");
+ case "D":
+ case "%a":
+ return t("ddd");
+ case "j":
+ case "%e":
+ return t("d");
+ case "l":
+ case "%A":
+ return t("dddd");
+ case "N":
+ case "%u":
+ return x.getDay() + 1;
+ case "S":
+ return t("S");
+ case "w":
+ case "%w":
+ return x.getDay();
+ case "z":
+ return x.getOrdinalNumber();
+ case "%j":
+ return p(x.getOrdinalNumber(), 3);
+ case "%U":
+ var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
+ d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
+ return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
+ case "W":
+ case "%V":
+ return x.getISOWeek();
+ case "%W":
+ return p(x.getWeek());
+ case "F":
+ case "%B":
+ return t("MMMM");
+ case "m":
+ case "%m":
+ return t("MM");
+ case "M":
+ case "%b":
+ case "%h":
+ return t("MMM");
+ case "n":
+ return t("M");
+ case "t":
+ return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
+ case "L":
+ return ($D.isLeapYear(x.getFullYear())) ? 1 : 0;
+ case "o":
+ case "%G":
+ return x.setWeek(x.getISOWeek()).toString("yyyy");
+ case "%g":
+ return x.$format("%G").slice(-2);
+ case "Y":
+ case "%Y":
+ return t("yyyy");
+ case "y":
+ case "%y":
+ return t("yy");
+ case "a":
+ case "%p":
+ return t("tt").toLowerCase();
+ case "A":
+ return t("tt").toUpperCase();
+ case "g":
+ case "%I":
+ return t("h");
+ case "G":
+ return t("H");
+ case "h":
+ return t("hh");
+ case "H":
+ case "%H":
+ return t("HH");
+ case "i":
+ case "%M":
+ return t("mm");
+ case "s":
+ case "%S":
+ return t("ss");
+ case "u":
+ return p(x.getMilliseconds(), 3);
+ case "I":
+ return (x.isDaylightSavingTime()) ? 1 : 0;
+ case "O":
+ return x.getUTCOffset();
+ case "P":
+ y = x.getUTCOffset();
+ return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
+ case "e":
+ case "T":
+ case "%z":
+ case "%Z":
+ return x.getTimezone();
+ case "Z":
+ return x.getTimezoneOffset() * -60;
+ case "B":
+ var now = new Date();
+ return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
+ case "c":
+ return x.toISOString().replace(/\"/g, "");
+ case "U":
+ return $D.strtotime("now");
+ case "%c":
+ return t("d") + " " + t("t");
+ case "%C":
+ return Math.floor(x.getFullYear() / 100 + 1);
+ case "%D":
+ return t("MM/dd/yy");
+ case "%n":
+ return "\\n";
+ case "%t":
+ return "\\t";
+ case "%r":
+ return t("hh:mm tt");
+ case "%R":
+ return t("H:mm");
+ case "%T":
+ return t("H:mm:ss");
+ case "%x":
+ return t("d");
+ case "%X":
+ return t("t");
+ default:
+ $f.push(m);
+ return m;
+ }
+ }
+ ) : this._toString();
+ };
+
+ if (!$P.format) {
+ $P.format = $P.$format;
+ }
+}());
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "fa-IR",
+ englishName: "Persian (Iran)",
+ nativeName: "فارسى (ايران)",
+
+ /* Day Name Strings */
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+ abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+ shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+ firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "ق.ظ",
+ pmDesignator: "ب.ظ",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "mdy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "M/d/yyyy",
+ longDate: "dddd, MMMM dd, yyyy",
+ shortTime: "hh:mm tt",
+ longTime: "hh:mm:ss tt",
+ fullDateTime: "dddd, MMMM dd, yyyy hh:mm:ss tt",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM, yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uary)?/i,
+ feb: /^feb(ruary)?/i,
+ mar: /^mar(ch)?/i,
+ apr: /^apr(il)?/i,
+ may: /^may/i,
+ jun: /^jun(e)?/i,
+ jul: /^jul(y)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^oct(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^su(n(day)?)?/i,
+ mon: /^mo(n(day)?)?/i,
+ tue: /^tu(e(s(day)?)?)?/i,
+ wed: /^we(d(nesday)?)?/i,
+ thu: /^th(u(r(s(day)?)?)?)?/i,
+ fri: /^fr(i(day)?)?/i,
+ sat: /^sa(t(urday)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "fi-FI",
+ englishName: "Finnish (Finland)",
+ nativeName: "suomi (Suomi)",
+
+ /* Day Name Strings */
+ dayNames: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai"],
+ abbreviatedDayNames: ["su", "ma", "ti", "ke", "to", "pe", "la"],
+ shortestDayNames: ["su", "ma", "ti", "ke", "to", "pe", "la"],
+ firstLetterDayNames: ["s", "m", "t", "k", "t", "p", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"],
+ abbreviatedMonthNames: ["tammi", "helmi", "maalis", "huhti", "touko", "kesä", "heinä", "elo", "syys", "loka", "marras", "joulu"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM'ta 'yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM'ta 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM'ta'",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^tammi(kuu)?/i,
+ feb: /^helmi(kuu)?/i,
+ mar: /^maalis(kuu)?/i,
+ apr: /^huhti(kuu)?/i,
+ may: /^touko(kuu)?/i,
+ jun: /^kesä(kuu)?/i,
+ jul: /^heinä(kuu)?/i,
+ aug: /^elo(kuu)?/i,
+ sep: /^syys(kuu)?/i,
+ oct: /^loka(kuu)?/i,
+ nov: /^marras(kuu)?/i,
+ dec: /^joulu(kuu)?/i,
+
+ sun: /^sunnuntai/i,
+ mon: /^maanantai/i,
+ tue: /^tiistai/i,
+ wed: /^keskiviikko/i,
+ thu: /^torstai/i,
+ fri: /^perjantai/i,
+ sat: /^lauantai/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "fr-FR",
+ englishName: "French (France)",
+ nativeName: "français (France)",
+
+ /* Day Name Strings */
+ dayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
+ abbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
+ shortestDayNames: ["di", "lu", "ma", "me", "je", "ve", "sa"],
+ firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
+ abbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc."],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd d MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd d MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^janv(.(ier)?)?/i,
+ feb: /^févr(.(ier)?)?/i,
+ mar: /^mars/i,
+ apr: /^avr(.(il)?)?/i,
+ may: /^mai/i,
+ jun: /^juin/i,
+ jul: /^juil(.(let)?)?/i,
+ aug: /^août/i,
+ sep: /^sept(.(embre)?)?/i,
+ oct: /^oct(.(obre)?)?/i,
+ nov: /^nov(.(embre)?)?/i,
+ dec: /^déc(.(embre)?)?/i,
+
+ sun: /^di(m(.(anche)?)?)?/i,
+ mon: /^lu(n(.(di)?)?)?/i,
+ tue: /^ma(r(.(di)?)?)?/i,
+ wed: /^me(r(.(credi)?)?)?/i,
+ thu: /^je(u(.(di)?)?)?/i,
+ fri: /^ve(n(.(dredi)?)?)?/i,
+ sat: /^sa(m(.(edi)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "gl-ES",
+ englishName: "Galician (Galician)",
+ nativeName: "galego (galego)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "luns", "martes", "mércores", "xoves", "venres", "sábado"],
+ abbreviatedDayNames: ["dom", "luns", "mar", "mér", "xov", "ven", "sab"],
+ shortestDayNames: ["do", "lu", "ma", "mé", "xo", "ve", "sa"],
+ firstLetterDayNames: ["d", "l", "m", "m", "x", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["xaneiro", "febreiro", "marzo", "abril", "maio", "xuño", "xullo", "agosto", "setembro", "outubro", "novembro", "decembro"],
+ abbreviatedMonthNames: ["xan", "feb", "mar", "abr", "maio", "xuñ", "xull", "ago", "set", "out", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "a.m.",
+ pmDesignator: "p.m.",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yy",
+ longDate: "dddd, dd' de 'MMMM' de 'yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^xan(eiro)?/i,
+ feb: /^feb(reiro)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^abr(il)?/i,
+ may: /^maio/i,
+ jun: /^xuñ(o)?/i,
+ jul: /^xull(o)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^set(embro)?/i,
+ oct: /^out(ubro)?/i,
+ nov: /^nov(embro)?/i,
+ dec: /^dec(embro)?/i,
+
+ sun: /^do(m(ingo)?)?/i,
+ mon: /^lu(1)?/i,
+ tue: /^ma(r(tes)?)?/i,
+ wed: /^mé(r(cores)?)?/i,
+ thu: /^xo(v(es)?)?/i,
+ fri: /^ve(n(res)?)?/i,
+ sat: /^sa(b(ado)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "he-IL",
+ englishName: "Hebrew (Israel)",
+ nativeName: "עברית (ישראל)",
+
+ /* Day Name Strings */
+ dayNames: ["יום ראשון", "יום שני", "יום שלישי", "יום רביעי", "יום חמישי", "יום שישי", "שבת"],
+ abbreviatedDayNames: ["יום א", "יום ב", "יום ג", "יום ד", "יום ה", "יום ו", "שבת"],
+ shortestDayNames: ["א", "ב", "ג", "ד", "ה", "ו", "ש"],
+ firstLetterDayNames: ["א", "ב", "ג", "ד", "ה", "ו", "ש"],
+
+ /* Month Name Strings */
+ monthNames: ["ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"],
+ abbreviatedMonthNames: ["ינו", "פבר", "מרץ", "אפר", "מאי", "יונ", "יול", "אוג", "ספט", "אוק", "נוב", "דצמ"],
+
+ /* AM/PM Designators */
+ amDesignator: "AM",
+ pmDesignator: "PM",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd dd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ינו(אר)?/i,
+ feb: /^פבר(ואר)?/i,
+ mar: /^מרץ/i,
+ apr: /^אפר(יל)?/i,
+ may: /^מאי/i,
+ jun: /^יונ(י)?/i,
+ jul: /^יול(י)?/i,
+ aug: /^אוג(וסט)?/i,
+ sep: /^ספט(מבר)?/i,
+ oct: /^אוק(טובר)?/i,
+ nov: /^נוב(מבר)?/i,
+ dec: /^דצמ(בר)?/i,
+
+ sun: /^א(ום א(אשון)?)?/i,
+ mon: /^ב(ום ב(ני)?)?/i,
+ tue: /^ג(ום ג(לישי)?)?/i,
+ wed: /^ד(ום ד(ביעי)?)?/i,
+ thu: /^ה(ום ה(מישי)?)?/i,
+ fri: /^ו(ום ו(ישי)?)?/i,
+ sat: /^ש(1)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "hu-HU",
+ englishName: "Hungarian (Hungary)",
+ nativeName: "magyar (Magyarország)",
+
+ /* Day Name Strings */
+ dayNames: ["vasárnap", "hétfő", "kedd", "szerda", "csütörtök", "péntek", "szombat"],
+ abbreviatedDayNames: ["V", "H", "K", "Sze", "Cs", "P", "Szo"],
+ shortestDayNames: ["V", "H", "K", "Sze", "Cs", "P", "Szo"],
+ firstLetterDayNames: ["V", "H", "K", "S", "C", "P", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["január", "február", "március", "április", "május", "június", "július", "augusztus", "szeptember", "október", "november", "december"],
+ abbreviatedMonthNames: ["jan.", "febr.", "márc.", "ápr.", "máj.", "jún.", "júl.", "aug.", "szept.", "okt.", "nov.", "dec."],
+
+ /* AM/PM Designators */
+ amDesignator: "de.",
+ pmDesignator: "du.",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy. MM. dd.",
+ longDate: "yyyy. MMMM d.",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "yyyy. MMMM d. H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM d.",
+ yearMonth: "yyyy. MMMM"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(.(uár)?)?/i,
+ feb: /^febr(.(uár)?)?/i,
+ mar: /^márc(.(ius)?)?/i,
+ apr: /^ápr(.(ilis)?)?/i,
+ may: /^máj(.(us)?)?/i,
+ jun: /^jún(.(ius)?)?/i,
+ jul: /^júl(.(ius)?)?/i,
+ aug: /^aug(.(usztus)?)?/i,
+ sep: /^szept(.(ember)?)?/i,
+ oct: /^okt(.(óber)?)?/i,
+ nov: /^nov(.(ember)?)?/i,
+ dec: /^dec(.(ember)?)?/i,
+
+ sun: /^vasárnap/i,
+ mon: /^hétfő/i,
+ tue: /^kedd/i,
+ wed: /^szerda/i,
+ thu: /^csütörtök/i,
+ fri: /^péntek/i,
+ sat: /^szombat/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "id-ID",
+ englishName: "Indonesian (Indonesia)",
+ nativeName: "Bahasa Indonesia (Indonesia)",
+
+ /* Day Name Strings */
+ dayNames: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"],
+ abbreviatedDayNames: ["Minggu", "Sen", "Sel", "Rabu", "Kamis", "Jumat", "Sabtu"],
+ shortestDayNames: ["M", "S", "S", "R", "K", "J", "S"],
+ firstLetterDayNames: ["M", "S", "S", "R", "K", "J", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "Nopember", "Desember"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agust", "Sep", "Okt", "Nop", "Des"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dd MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dd MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uari)?/i,
+ feb: /^feb(ruari)?/i,
+ mar: /^mar(et)?/i,
+ apr: /^apr(il)?/i,
+ may: /^mei/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^agust(us)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nop(ember)?/i,
+ dec: /^des(ember)?/i,
+
+ sun: /^m(1)?/i,
+ mon: /^s(en(in)?)?/i,
+ tue: /^s(el(asa)?)?/i,
+ wed: /^r(1)?/i,
+ thu: /^k(1)?/i,
+ fri: /^j(1)?/i,
+ sat: /^s(1)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "is-IS",
+ englishName: "Icelandic (Iceland)",
+ nativeName: "íslenska (Ísland)",
+
+ /* Day Name Strings */
+ dayNames: ["sunnudagur", "mánudagur", "þriðjudagur", "miðvikudagur", "fimmtudagur", "föstudagur", "laugardagur"],
+ abbreviatedDayNames: ["sun.", "mán.", "þri.", "mið.", "fim.", "fös.", "lau."],
+ shortestDayNames: ["su", "má", "þr", "mi", "fi", "fö", "la"],
+ firstLetterDayNames: ["s", "m", "þ", "m", "f", "f", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["janúar", "febrúar", "mars", "apríl", "maí", "júní", "júlí", "ágúst", "september", "október", "nóvember", "desember"],
+ abbreviatedMonthNames: ["jan.", "feb.", "mar.", "apr.", "maí", "jún.", "júl.", "ágú.", "sep.", "okt.", "nóv.", "des."],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(.(úar)?)?/i,
+ feb: /^feb(.(rúar)?)?/i,
+ mar: /^mar(.(s)?)?/i,
+ apr: /^apr(.(íl)?)?/i,
+ may: /^maí/i,
+ jun: /^jún(.(í)?)?/i,
+ jul: /^júl(.(í)?)?/i,
+ aug: /^ágú(.(st)?)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(.(óber)?)?/i,
+ nov: /^nóv(.(ember)?)?/i,
+ dec: /^des(.(ember)?)?/i,
+
+ sun: /^su(n(.(nudagur)?)?)?/i,
+ mon: /^má(n(.(udagur)?)?)?/i,
+ tue: /^þr(i(.(ðjudagur)?)?)?/i,
+ wed: /^mi(ð(.(vikudagur)?)?)?/i,
+ thu: /^fi(m(.(mtudagur)?)?)?/i,
+ fri: /^fö(s(.(tudagur)?)?)?/i,
+ sat: /^la(u(.(gardagur)?)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "it-IT",
+ englishName: "Italian (Italy)",
+ nativeName: "italiano (Italia)",
+
+ /* Day Name Strings */
+ dayNames: ["domenica", "lunedì", "martedì", "mercoledì", "giovedì", "venerdì", "sabato"],
+ abbreviatedDayNames: ["dom", "lun", "mar", "mer", "gio", "ven", "sab"],
+ shortestDayNames: ["do", "lu", "ma", "me", "gi", "ve", "sa"],
+ firstLetterDayNames: ["d", "l", "m", "m", "g", "v", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre"],
+ abbreviatedMonthNames: ["gen", "feb", "mar", "apr", "mag", "giu", "lug", "ago", "set", "ott", "nov", "dic"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd/MM/yyyy",
+ longDate: "dddd d MMMM yyyy",
+ shortTime: "H.mm",
+ longTime: "H.mm.ss",
+ fullDateTime: "dddd d MMMM yyyy H.mm.ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^gen(naio)?/i,
+ feb: /^feb(braio)?/i,
+ mar: /^mar(zo)?/i,
+ apr: /^apr(ile)?/i,
+ may: /^mag(gio)?/i,
+ jun: /^giu(gno)?/i,
+ jul: /^lug(lio)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^set(tembre)?/i,
+ oct: /^ott(obre)?/i,
+ nov: /^nov(embre)?/i,
+ dec: /^dic(embre)?/i,
+
+ sun: /^do(m(enica)?)?/i,
+ mon: /^lu(n(edì)?)?/i,
+ tue: /^ma(r(tedì)?)?/i,
+ wed: /^me(r(coledì)?)?/i,
+ thu: /^gi(o(vedì)?)?/i,
+ fri: /^ve(n(erdì)?)?/i,
+ sat: /^sa(b(ato)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ja-JP",
+ englishName: "Japanese (Japan)",
+ nativeName: "日本語 (日本)",
+
+ /* Day Name Strings */
+ dayNames: ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"],
+ abbreviatedDayNames: ["日", "月", "火", "水", "木", "金", "土"],
+ shortestDayNames: ["日", "月", "火", "水", "木", "金", "土"],
+ firstLetterDayNames: ["日", "月", "火", "水", "木", "金", "土"],
+
+ /* Month Name Strings */
+ monthNames: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
+ abbreviatedMonthNames: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
+
+ /* AM/PM Designators */
+ amDesignator: "午前",
+ pmDesignator: "午後",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/MM/dd",
+ longDate: "yyyy'年'M'月'd'日'",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "yyyy'年'M'月'd'日' H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "M'月'd'日'",
+ yearMonth: "yyyy'年'M'月'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^1(月)?/i,
+ feb: /^2(月)?/i,
+ mar: /^3(月)?/i,
+ apr: /^4(月)?/i,
+ may: /^5(月)?/i,
+ jun: /^6(月)?/i,
+ jul: /^7(月)?/i,
+ aug: /^8(月)?/i,
+ sep: /^9(月)?/i,
+ oct: /^10(月)?/i,
+ nov: /^11(月)?/i,
+ dec: /^12(月)?/i,
+
+ sun: /^日曜日/i,
+ mon: /^月曜日/i,
+ tue: /^火曜日/i,
+ wed: /^水曜日/i,
+ thu: /^木曜日/i,
+ fri: /^金曜日/i,
+ sat: /^土曜日/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ko-KR",
+ englishName: "Korean (Korea)",
+ nativeName: "한국어 (대한민국)",
+
+ /* Day Name Strings */
+ dayNames: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"],
+ abbreviatedDayNames: ["일", "월", "화", "수", "목", "금", "토"],
+ shortestDayNames: ["일", "월", "화", "수", "목", "금", "토"],
+ firstLetterDayNames: ["일", "월", "화", "수", "목", "금", "토"],
+
+ /* Month Name Strings */
+ monthNames: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"],
+ abbreviatedMonthNames: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
+
+ /* AM/PM Designators */
+ amDesignator: "오전",
+ pmDesignator: "오후",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy-MM-dd",
+ longDate: "yyyy'년' M'월' d'일' dddd",
+ shortTime: "tt h:mm",
+ longTime: "tt h:mm:ss",
+ fullDateTime: "yyyy'년' M'월' d'일' dddd tt h:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "M'월' d'일'",
+ yearMonth: "yyyy'년' M'월'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^1(월)?/i,
+ feb: /^2(월)?/i,
+ mar: /^3(월)?/i,
+ apr: /^4(월)?/i,
+ may: /^5(월)?/i,
+ jun: /^6(월)?/i,
+ jul: /^7(월)?/i,
+ aug: /^8(월)?/i,
+ sep: /^9(월)?/i,
+ oct: /^10(월)?/i,
+ nov: /^11(월)?/i,
+ dec: /^12(월)?/i,
+
+ sun: /^일요일/i,
+ mon: /^월요일/i,
+ tue: /^화요일/i,
+ wed: /^수요일/i,
+ thu: /^목요일/i,
+ fri: /^금요일/i,
+ sat: /^토요일/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+/**
+ * kronolith.js - Base application logic.
+ * NOTE: ContextSensitive.js must be loaded before this file.
+ *
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Jan Schneider <jan@horde.org>
+ */
+
+/* Trick some Horde js into thinking this is the parent Horde window. */
+var frames = { horde_main: true },
+
+/* Kronolith object. */
+KronolithCore = {
+ // Vars used and defaulting to null/false:
+ // DMenu, Growler, inAjaxCallback, is_logout, onDoActionComplete,
+ // eventForm, daySizes, viewLoading
+
+ view: '',
+ ecache: $H(),
+ tcache: $H(),
+ efifo: {},
+ eventsLoading: $H(),
+ loading: 0,
+ date: new Date(),
+ taskType: 1, //Default to all tasks view
+
+ doActionOpts: {
+ onException: function(r, e) { KronolitCore.debug('onException', e); },
+ onFailure: function(t, o) { KronolithCore.debug('onFailure', t); },
+ evalJS: false,
+ evalJSON: true
+ },
+
+ debug: function(label, e)
+ {
+ if (!this.is_logout && Kronolith.conf.debug) {
+ alert(label + ': ' + (e instanceof Error ? e.name + '-' + e.message : Object.inspect(e)));
+ }
+ },
+
+ /* 'action' -> if action begins with a '*', the exact string will be used
+ * instead of sending the action to the ajax handler. */
+ doAction: function(action, params, callback, opts)
+ {
+ var b, tmp = {};
+
+ opts = Object.extend(this.doActionOpts, opts || {});
+ params = $H(params);
+ action = action.startsWith('*')
+ ? action.substring(1)
+ : Kronolith.conf.URI_AJAX + '/' + action;
+ if (Kronolith.conf.SESSION_ID) {
+ params.update(Kronolith.conf.SESSION_ID.toQueryParams());
+ }
+ opts.parameters = params.toQueryString();
+ opts.onComplete = function(t, o) { this.doActionComplete(t, callback); }.bind(this);
+ new Ajax.Request(action, opts);
+ },
+
+ doActionComplete: function(request, callback)
+ {
+ this.inAjaxCallback = true;
+
+ if (!request.responseJSON) {
+ if (++this.server_error == 3) {
+ this.showNotifications([ { type: 'horde.error', message: Kronolith.text.ajax_timeout } ]);
+ }
+ this.inAjaxCallback = false;
+ return;
+ }
+
+ var r = request.responseJSON;
+
+ if (!r.msgs) {
+ r.msgs = [];
+ }
+
+ if (r.response && Object.isFunction(callback)) {
+ try {
+ callback(r);
+ } catch (e) {
+ this.debug('doActionComplete', e);
+ }
+ }
+
+ if (this.server_error >= 3) {
+ r.msgs.push({ type: 'horde.success', message: Kronolith.text.ajax_recover });
+ }
+ this.server_error = 0;
+
+ if (!r.msgs_noauto) {
+ this.showNotifications(r.msgs);
+ }
+
+ if (this.onDoActionComplete) {
+ this.onDoActionComplete(r);
+ }
+
+ this.inAjaxCallback = false;
+ },
+
+ setTitle: function(title)
+ {
+ document.title = Kronolith.conf.name + ' :: ' + title;
+ return title;
+ },
+
+ showNotifications: function(msgs)
+ {
+ if (!msgs.size() || this.is_logout) {
+ return;
+ }
+
+ msgs.find(function(m) {
+ switch (m.type) {
+ case 'kronolith.timeout':
+ this.logout(Kronolith.conf.timeout_url);
+ return true;
+
+ case 'horde.error':
+ case 'horde.message':
+ case 'horde.success':
+ case 'horde.warning':
+ this.Growler.growl(m.message, {
+ className: m.type.replace('.', '-'),
+ life: 8,
+ log: true,
+ sticky: m.type == 'horde.error'
+ });
+ }
+ }, this);
+ },
+
+ logout: function(url)
+ {
+ this.is_logout = true;
+ this.redirect(url || (Kronolith.conf.URI_IMP + '/LogOut'));
+ },
+
+ redirect: function(url)
+ {
+ url = this.addSID(url);
+ if (parent.frames.horde_main) {
+ parent.location = url;
+ } else {
+ window.location = url;
+ }
+ },
+
+ addSID: function(url)
+ {
+ if (!Kronolith.conf.SESSION_ID) {
+ return url;
+ }
+ return this.addURLParam(url, Kronolith.conf.SESSION_ID.toQueryParams());
+ },
+
+ addURLParam: function(url, params)
+ {
+ var q = url.indexOf('?');
+
+ if (q != -1) {
+ params = $H(url.toQueryParams()).merge(params).toObject();
+ url = url.substring(0, q);
+ }
+ return url + '?' + Object.toQueryString(params);
+ },
+
+ go: function(fullloc, data)
+ {
+ var locParts = fullloc.split(':');
+ var loc = locParts.shift();
+
+ switch (loc) {
+ case 'day':
+ case 'week':
+ case 'month':
+ case 'year':
+ case 'agenda':
+ case 'tasks':
+ var locCap = loc.capitalize();
+ [ 'Day', 'Week', 'Month', 'Year', 'Tasks', 'Agenda' ].each(function(a) {
+ $('kronolithNav' + a).removeClassName('on');
+ });
+ $('kronolithNav' + locCap).addClassName('on');
+ if (this.view && this.view != loc) {
+ $('kronolithView' + this.view.capitalize()).fade({ 'queue': 'end' });
+ }
+
+ switch (loc) {
+ case 'day':
+ case 'agenda':
+ case 'week':
+ case 'month':
+ case 'year':
+ var date = locParts.shift();
+ if (date) {
+ date = this.parseDate(date);
+ } else {
+ date = this.date;
+ }
+
+ if (this.view == loc && date.getYear() == this.date.getYear() &&
+ ((loc == 'year') ||
+ (loc == 'month' && date.getMonth() == this.date.getMonth()) ||
+ (loc == 'week' && date.getWeek() == this.date.getWeek()) ||
+ ((loc == 'day' || loc == 'agenda') && date.dateString() == this.date.dateString()))) {
+ return;
+ }
+
+ this.updateView(date, loc);
+ var dates = this.viewDates(date, loc);
+ this._loadEvents(dates[0], dates[1], loc);
+ if ($('kronolithView' + locCap)) {
+ this.viewLoading = true;
+ $('kronolithView' + locCap).appear({ 'queue': 'end', 'afterFinish': function() { this.viewLoading = false; }.bind(this) });
+ }
+ $('kronolithLoading' + loc).insert($('kronolithLoading').remove());
+ this.updateMinical(date, loc);
+ this.date = date;
+
+ break;
+
+ case 'tasks':
+ if (this.view == loc) {
+ return;
+ }
+ this._loadTasks(this.taskType);
+ if ($('kronolithView' + locCap)) {
+ this.viewLoading = true;
+ $('kronolithView' + locCap).appear({ 'queue': 'end', 'afterFinish': function() { this.viewLoading = false; }.bind(this) });
+ }
+ $('kronolithLoading' + loc).insert($('kronolithLoading').remove());
+ this.updateMinical(this.date, loc);
+
+ break;
+
+ default:
+ if ($('kronolithView' + locCap)) {
+ this.viewLoading = true;
+ $('kronolithView' + locCap).appear({ 'queue': 'end', 'afterFinish': function() { this.viewLoading = false; }.bind(this) });
+ }
+ break;
+ }
+
+ this._addHistory(fullloc);
+ this.view = loc;
+ break;
+
+ case 'search':
+ [ 'Day', 'Week', 'Month', 'Year', 'Tasks', 'Agenda' ].each(function(a) {
+ $('kronolithNav' + a).removeClassName('on');
+ });
+ if (this.view) {
+ $('kronolithView' + this.view.capitalize()).fade({ 'queue': 'end' });
+ }
+ var cals = [], term = locParts[1],
+ query = Object.toJSON({ 'title': term });
+ this.updateView(null, 'search', term);
+ $H(Kronolith.conf.calendars).each(function(type) {
+ $H(type.value).each(function(calendar) {
+ if (calendar.value.show) {
+ cals.push(type.key + '|' + calendar.key);
+ }
+ });
+ });
+ this.startLoading('search', query, '');
+ this.doAction('Search' + locParts[0],
+ { 'cals': cals.toJSON(), 'query': query },
+ function(r) {
+ // Hide spinner.
+ this.loading--;
+ if (!this.loading) {
+ $('kronolithLoading').hide();
+ }
+ if (r.response.view != 'search' ||
+ r.response.query != this.eventsLoading['search'] ||
+ Object.isUndefined(r.response.events)) {
+ return;
+ }
+ $H(r.response.events).each(function(calendars) {
+ $H(calendars.value).each(function(events) {
+ this.createAgendaDay(events.key);
+ $H(events.value).each(function(event) {
+ event.value.calendar = calendars.key;
+ event.value.start = Date.parse(event.value.s);
+ event.value.end = Date.parse(event.value.e);
+ this._insertEvent(event, events.key, 'agenda');
+ }, this);
+ }, this);
+ }, this);
+ }.bind(this));
+ this.viewLoading = true;
+ $('kronolithViewAgenda').appear({ 'queue': 'end', 'afterFinish': function() { this.viewLoading = false; }.bind(this) });
+ $('kronolithLoadingagenda').insert($('kronolithLoading').remove());
+ this.updateMinical(this.date, 'search');
+ this._addHistory(fullloc);
+ this.view = 'agenda';
+ break;
+
+ case 'event':
+ if (!this.view) {
+ this.go(Kronolith.conf.login_view);
+ this.go.bind(this, fullloc, data).defer();
+ return;
+ }
+ switch (locParts.length) {
+ case 0:
+ this.editEvent();
+ break;
+ case 1:
+ this.editEvent(null, null, locParts[0]);
+ break;
+ case 2:
+ this.editEvent(locParts[0], locParts[1]);
+ break;
+ }
+ this.updateMinical(this.date, this.view);
+ this._addHistory(fullloc);
+ break;
+
+ case 'options':
+ //this.highlightSidebar('appoptions');
+ this._addHistory(loc);
+ this.setTitle(Kronolith.text.prefs);
+ this.iframeContent(loc, Kronolith.conf.prefs_url);
+ break;
+ }
+ },
+
+ /**
+ * Rebuilds one of the calendar views for a new date.
+ *
+ * @param Date date The date to show in the calendar.
+ * @param string view The view that's rebuilt.
+ * @param mixed data Any additional data that might be required.
+ */
+ updateView: function(date, view, data)
+ {
+ switch (view) {
+ case 'day':
+ this.dayEvents = [];
+ this.dayGroups = [];
+ this.allDayEvents = [];
+ $('kronolithViewDay').down('caption span').innerHTML = this.setTitle(date.toString('D'));
+ break;
+
+ case 'week':
+ this.dayEvents = [];
+ this.dayGroups = [];
+ this.allDayEvents = [];
+ var div = $('kronolithEventsWeek').down('div'),
+ th = $('kronolithViewWeekHead').down('.kronolithWeekDay'),
+ td = $('kronolithViewWeekBody').down('td').next('td'),
+ dates = this.viewDates(date, view),
+ day = dates[0].clone();
+
+ $('kronolithViewWeek').down('caption span').innerHTML = this.setTitle(Kronolith.text.week.interpolate({ 'week': date.getWeek() }));
+
+ for (var i = 0; i < 7; i++) {
+ div.writeAttribute('id', 'kronolithEventsWeek' + day.dateString());
+ th.writeAttribute('date', day.dateString()).down('span').innerHTML = day.toString('dddd, d');
+ td.down('div').writeAttribute('id', 'kronolithAllDay' + day.dateString());
+ div = div.next('div');
+ th = th.next('td');
+ td = td.next('td');
+ day.next().day();
+ }
+ break;
+
+ case 'month':
+ var tbody = $('kronolithViewMonthBody'),
+ dates = this.viewDates(date, view),
+ day = dates[0].clone(), row;
+
+ $('kronolithViewMonth').down('caption span').innerHTML = this.setTitle(date.toString('MMMM yyyy'));
+
+ // Remove old rows. Maybe we should only rebuild the calendars if
+ // necessary.
+ tbody.childElements().each(function(row) {
+ if (row.identify() != 'kronolithRowTemplate') {
+ row.remove();
+ }
+ });
+
+ // Build new calendar view.
+ while (!day.isAfter(dates[1])) {
+ tbody.insert(this.createWeekRow(day, date.getMonth(), dates).show());
+ day.next().week();
+ }
+ this._equalRowHeights(tbody);
+
+ break;
+
+ case 'year':
+ var viewBody = $('kronolithViewYear'), month;
+
+ viewBody.down('caption span').innerHTML = this.setTitle(date.toString('yyyy'));
+
+ // Build new calendar view.
+ for (month = 0; month < 12; month++) {
+ $('kronolithYear' + month).update(this.createYearMonth(date.getFullYear(), month).show());
+ }
+
+ break;
+
+ case 'agenda':
+ case 'search':
+ // Agenda days are only created on demand, if there are any events
+ // to add.
+ if (view == 'agenda') {
+ var dates = this.viewDates(date, view),
+ day = dates[0].clone();
+ $('kronolithViewAgenda').down('caption span').innerHTML = this.setTitle(Kronolith.text.agenda + ' ' + dates[0].toString('d') + ' - ' + dates[1].toString('d'));
+ } else {
+ $('kronolithViewAgenda').down('caption span').update(this.setTitle(Kronolith.text.searching.interpolate({ 'term': data })));
+ }
+
+ // Remove old rows. Maybe we should only rebuild the calendars if
+ // necessary.
+ tbody = $('kronolithViewAgendaBody').childElements().each(function(row) {
+ if (row.identify() != 'kronolithAgendaTemplate') {
+ row.remove();
+ }
+ });
+
+ break;
+ }
+ },
+
+ /**
+ * Creates a single row of day cells for usage in the month and multi-week
+ * views.
+ *
+ * @param Date date The first day to show in the row.
+ * @param integer month The current month. Days not from the current
+ * month get the kronolithOtherMonth CSS class
+ * assigned.
+ * @param array viewDates Array of Date objects with the start and end
+ * dates of the view.
+ *
+ * @return Element The element rendering a week row.
+ */
+ createWeekRow: function(date, month, viewDates)
+ {
+ var monday = date.clone(), day = date.clone(),
+ today = new Date().dateString(),
+ start = viewDates[0].dateString(), end = viewDates[1].dateString(),
+ row, cell, dateString;
+
+ // Find monday of the week, to determine the week number.
+ if (monday.getDay() != 1) {
+ monday.moveToDayOfWeek(1, 1);
+ }
+
+ // Create a copy of the row template.
+ row = $('kronolithRowTemplate').cloneNode(true);
+ row.removeAttribute('id');
+
+ // Fill week number and day cells.
+ cell = row.down()
+ .setText(monday.getWeek())
+ .writeAttribute('date', monday.dateString())
+ .next();
+ while (cell) {
+ dateString = day.dateString();
+ cell.id = 'kronolithMonthDay' + dateString;
+ cell.writeAttribute('date', dateString);
+ cell.removeClassName('kronolithOtherMonth').removeClassName('kronolithToday');
+ if (day.getMonth() != month) {
+ cell.addClassName('kronolithOtherMonth');
+ }
+ if (dateString == today) {
+ cell.addClassName('kronolithToday');
+ }
+ new Drop(cell, { onDrop: function(drop) {
+ var el = DragDrop.Drags.drag.element,
+ eventid = el.readAttribute('eventid'),
+ cal = el.readAttribute('calendar');
+ if (drop == el.parentNode) {
+ return;
+ }
+ drop.insert(el);
+ this.startLoading(cal, start, end);
+ this.doAction('UpdateEvent',
+ { 'cal': cal,
+ 'id': eventid,
+ 'view': this.view,
+ 'view_start': start,
+ 'view_end': end,
+ 'att': $H({ start_date: drop.readAttribute('date') }).toJSON() },
+ function(r) {
+ if (r.response.events) {
+ this._removeEvent(eventid, cal);
+ }
+ this._loadEventsCallback(r);
+ }.bind(this));
+ }.bind(this) });
+ cell.down('.kronolithDay')
+ .writeAttribute('date', dateString)
+ .innerHTML = day.getDate();
+ cell.down('.kronolithAddEvent')
+ .writeAttribute('date', dateString);
+ cell = cell.next();
+ day.add(1).day();
+ }
+
+ return row;
+ },
+
+ /**
+ * Creates a table row for a single day in the agenda view, if it doesn't
+ * exist yet.
+ *
+ * @param string date The day to show in the row.
+ *
+ * @return Element The element rendering a week row.
+ */
+ createAgendaDay: function(date)
+ {
+ // Exit if row exists already.
+ if ($('kronolithAgendaDay' + date)) {
+ return;
+ }
+
+ // Create a copy of the row template.
+ var body = $('kronolithViewAgendaBody'),
+ row = $('kronolithAgendaTemplate').cloneNode(true);
+ row.removeAttribute('id');
+
+ // Fill week number and day cells.
+ row.addClassName('kronolithRow' + (body.select('tr').length % 2 == 1 ? 'Odd' : 'Even'))
+ .down()
+ .setText(this.parseDate(date).toString('D'))
+ .writeAttribute('date', date)
+ .next()
+ .writeAttribute('id', 'kronolithAgendaDay' + date);
+
+ // Insert row.
+ var nextRow;
+ body.childElements().each(function(elm) {
+ if (elm.down().readAttribute('date') > date) {
+ nextRow = elm;
+ return;
+ }
+ });
+ if (nextRow) {
+ nextRow.insert({ 'before': row.show() });
+ } else {
+ body.insert(row.show());
+ }
+
+ return row;
+ },
+
+ /**
+ * Creates a table for a single month in the year view.
+ *
+ * @param integer year The year.
+ * @param integer month The month.
+ *
+ * @return Element The element rendering a month table.
+ */
+ createYearMonth: function(year, month)
+ {
+ // Create a copy of the month template.
+ var table = $('kronolithYearTemplate').cloneNode(true),
+ tbody = table.down('tbody');
+ table.removeAttribute('id');
+ tbody.writeAttribute('id', 'kronolithYearTable' + month)
+
+ // Set month name.
+ table.down('SPAN')
+ .writeAttribute('date', year.toPaddedString(4) + (month + 1).toPaddedString(2) + '01')
+ .innerHTML = Date.CultureInfo.monthNames[month];
+
+ // Build month table.
+ this.buildMinical(tbody, new Date(year, month, 1));
+
+ return table;
+ },
+
+ _equalRowHeights: function(tbody)
+ {
+ var children = tbody.childElements();
+ children.invoke('setStyle', { 'height': (100 / (children.size() - 1)) + '%' });
+ },
+
+ /**
+ * Calculates some dimensions for the day and week view.
+ *
+ * @param string storage Property name where the dimensions are stored.
+ * @param string view DOM node ID of the view.
+ */
+ _calculateRowSizes: function(storage, view)
+ {
+ if (!Object.isUndefined(this[storage])) {
+ return;
+ }
+
+ this[storage] = {};
+ var trA = $(view).down('.kronolithAllDay'),
+ tdA = trA.down('td'),
+ tr = trA.next('tr'),
+ td = tr.down('td'), height;
+ this[storage].offset = tr.offsetTop - trA.offsetTop;
+ this[storage].height = tr.next('tr').offsetTop - tr.offsetTop;
+ this[storage].spacing = this[storage].height - tr.getHeight()
+ + parseInt(td.getStyle('borderTopWidth'))
+ + parseInt(td.getStyle('borderBottomWidth'));
+ this[storage].allDay = tr.offsetTop - trA.offsetTop;
+ this[storage].allDay -= this[storage].allDay - trA.getHeight()
+ + parseInt(td.getStyle('borderTopWidth'))
+ + parseInt(tdA.getStyle('borderBottomWidth'));
+ },
+
+ /**
+ * Rebuilds the mini calendar.
+ *
+ * @param Date date The date to show in the calendar.
+ * @param string view The view that's displayed, determines which days in
+ * the mini calendar are highlighted.
+ */
+ updateMinical: function(date, view)
+ {
+ // Update header.
+ $('kronolithMinicalDate').writeAttribute('date', date.dateString()).innerHTML = date.toString('MMMM yyyy');
+
+ this.buildMinical($('kronolithMinical').down('tbody'), date, view);
+
+ $('kronolithMenuCalendars').setStyle({ 'bottom': $('kronolithMenuBottom').getHeight() + 'px' });
+ },
+
+ /**
+ * Creates a mini calendar suitable for the navigation calendar and the
+ * year view.
+ *
+ * @param Element tbody The table body to add the days to.
+ * @param Date date The date to show in the calendar.
+ * @param string view The view that's displayed, determines which days in
+ * the mini calendar are highlighted.
+ */
+ buildMinical: function(tbody, date, view)
+ {
+ var dates = this.viewDates(date, 'month'), day = dates[0].clone(),
+ date7 = date.clone().add(1).week(),
+ weekStart, weekEnd, weekEndDay, td, tr;
+
+ // Remove old calendar rows. Maybe we should only rebuild the minical
+ // if necessary.
+ tbody.childElements().invoke('remove');
+
+ while (day.compareTo(dates[1]) < 1) {
+ // Create calendar row and insert week number.
+ if (day.getDay() == Kronolith.conf.week_start) {
+ tr = new Element('tr');
+ tbody.insert(tr);
+ td = new Element('td', { 'class': 'kronolithMinicalWeek', 'weekdate': day.dateString() }).innerHTML = day.getWeek();
+ tr.insert(td);
+ weekStart = day.clone();
+ weekEnd = day.clone();
+ weekEnd.add(6).days();
+ }
+ // Insert day cell.
+ td = new Element('td', {date: day.dateString()});
+ if (day.getMonth() != date.getMonth()) {
+ td.addClassName('kronolithMinicalEmpty');
+ }
+ // Highlight days currently being displayed.
+ if (view &&
+ (view == 'month' ||
+ (view == 'week' && date.between(weekStart, weekEnd)) ||
+ (view == 'day' && date.equals(day)) ||
+ (view == 'agenda' && !day.isBefore(date) && day.isBefore(date7)))) {
+ td.addClassName('kronolithSelected');
+ }
+ td.innerHTML = day.getDate();
+ tr.insert(td);
+ day.next().day();
+ }
+ },
+
+ /**
+ * Rebuilds the list of calendars.
+ */
+ updateCalendarList: function()
+ {
+ var my = 0, shared = 0, ext = {}, extNames = {},
+ remote, api, div;
+
+ $H(Kronolith.conf.calendars.internal).each(function(cal) {
+ if (cal.value.owner) {
+ my++;
+ div = $('kronolithMyCalendars');
+ } else {
+ shared++;
+ div = $('kronolithSharedCalendars');
+ }
+ div.insert(new Element('DIV', { 'calendar': cal.key, 'calendarclass': 'internal', 'class': cal.value.show ? 'kronolithCalOn' : 'kronolithCalOff' })
+ .setStyle({ backgroundColor: cal.value.bg, color: cal.value.fg })
+ .update(cal.value.name));
+ });
+ if (my) {
+ $('kronolithMyCalendars').show();
+ } else {
+ $('kronolithMyCalendars').hide();
+ }
+ if (shared) {
+ $('kronolithSharedCalendars').show();
+ } else {
+ $('kronolithSharedCalendars').hide();
+ }
+
+ $H(Kronolith.conf.calendars.external).each(function(cal) {
+ api = cal.key.split('/');
+ if (typeof ext[api[0]] == 'undefined') {
+ ext[api[0]] = {};
+ }
+ ext[api[0]][api[1]] = cal.value;
+ extNames[api[0]] = cal.value.api;
+ });
+ $H(ext).each(function(api) {
+ $('kronolithExternalCalendars')
+ .insert(new Element('H3')
+ .insert(new Element('A', { 'class': 'kronolithAdd' })
+ .update('+'))
+ .insert({ bottom: extNames[api.key] }))
+ .insert(new Element('DIV', { 'id': 'kronolithExternalCalendar' + api.key, 'class': 'kronolithCalendars' }));
+ $H(api.value).each(function(cal) {
+ $('kronolithExternalCalendar' + api.key)
+ .insert(new Element('DIV', { 'calendar': api.key + '/' + cal.key, 'calendarclass': 'external', 'class': cal.value.show ? 'kronolithCalOn' : 'kronolithCalOff' })
+ .setStyle({ backgroundColor: cal.value.bg, color: cal.value.fg })
+ .update(cal.value.name));
+ });
+ });
+
+ remote = $H(Kronolith.conf.calendars.remote);
+ remote.each(function(cal) {
+ $('kronolithRemoteCalendars')
+ .insert(new Element('DIV', { 'calendar': cal.key, 'calendarclass': 'remote', 'class': cal.value.show ? 'kronolithCalOn' : 'kronolithCalOff' })
+ .setStyle({ backgroundColor: cal.value.bg, color: cal.value.fg })
+ .update(cal.value.name));
+ });
+ if (remote.size()) {
+ $('kronolithRemoteCalendars').show();
+ } else {
+ $('kronolithRemoteCalendars').hide();
+ }
+ },
+
+ /**
+ * Sets the load signature and show the loading spinner.
+ *
+ * @param string cal The loading calendar.
+ * @param string start The first day of the loading view.
+ * @param string end The last day of the loading view.
+ */
+ startLoading: function(cal, start, end)
+ {
+ this.eventsLoading[cal] = start + end;
+ this.loading++;
+ $('kronolithLoading').show();
+ },
+
+ /**
+ */
+ _loadEvents: function(firstDay, lastDay, view, calendars)
+ {
+ if (typeof calendars == 'undefined') {
+ calendars = [];
+ $H(Kronolith.conf.calendars).each(function(type) {
+ $H(type.value).each(function(cal) {
+ if (cal.value.show) {
+ calendars.push([type.key, cal.key]);
+ }
+ });
+ });
+ }
+
+ calendars.each(function(cal) {
+ var startDay = firstDay.clone(), endDay = lastDay.clone(),
+ cals = this.ecache.get(cal[0]),
+ events, date;
+
+ if (typeof cals != 'undefined' &&
+ typeof cals.get(cal[1]) != 'undefined') {
+ cals = cals.get(cal[1]);
+ while (!Object.isUndefined(cals.get(startDay.dateString())) &&
+ startDay.isBefore(endDay)) {
+ this._insertEvents([startDay, startDay], view, cal.join('|'));
+ startDay.add(1).day();
+ }
+ while (!Object.isUndefined(cals.get(endDay.dateString())) &&
+ (!startDay.isAfter(endDay))) {
+ this._insertEvents([endDay, endDay], view, cal.join('|'));
+ endDay.add(-1).day();
+ }
+ if (startDay.compareTo(endDay) > 0) {
+ return;
+ }
+ }
+ var start = startDay.dateString(), end = endDay.dateString(),
+ calendar = cal.join('|');
+ this.startLoading(calendar, start, end);
+ this._storeCache($H(), calendar);
+ this.doAction('ListEvents', { start: start, end: end, cal: calendar, view: view }, this._loadEventsCallback.bind(this));
+ }, this);
+ },
+
+ /**
+ * Callback method for inserting events in the current view.
+ *
+ * @param object r The ajax response object.
+ */
+ _loadEventsCallback: function(r)
+ {
+ // Hide spinner.
+ this.loading--;
+ if (!this.loading) {
+ $('kronolithLoading').hide();
+ }
+
+ var start = this.parseDate(r.response.sig.substr(0, 8)),
+ end = this.parseDate(r.response.sig.substr(8, 8)),
+ dates = [start, end];
+
+ this._storeCache(r.response.events || {}, r.response.cal, dates);
+
+ // Check if this is the still the result of the most current request.
+ if (r.response.view != this.view ||
+ r.response.sig != this.eventsLoading[r.response.cal]) {
+ return;
+ }
+
+ this._insertEvents(dates, this.view, r.response.cal);
+ },
+
+ /**
+ * Reads events from the cache and inserts them into the view.
+ *
+ * If inserting events into day and week views, the calendar parameter is
+ * ignored, and events from all visible calendars are inserted instead.
+ * This is necessary because the complete view has to be re-rendered if
+ * events are not in chronological order.
+ * The year view is specially handled too because there are no individual
+ * events, only a summary of all events per day.
+ *
+ * @param Array dates Start and end of dates to process.
+ * @param string view The view to update.
+ * @param string calendar The calendar to update.
+ */
+ _insertEvents: function(dates, view, calendar)
+ {
+ switch (view) {
+ case 'day':
+ case 'week':
+ // The day and week views require the view to be completely
+ // loaded, to correctly calculate the dimensions.
+ if (this.viewLoading || this.view != view) {
+ this._insertEvents.bind(this, [dates[0].clone(), dates[1].clone()], view, calendar).defer();
+ return;
+ }
+ break;
+ }
+
+ var day = dates[0].clone(), date;
+ while (!day.isAfter(dates[1])) {
+ date = day.dateString();
+ switch (view) {
+ case 'day':
+ case 'week':
+ this.dayEvents = [];
+ this.dayGroups = [];
+ this.allDayEvents = [];
+ if (view == 'day') {
+ $$('.kronolithEvent').invoke('remove');
+ } else {
+ $('kronolithEventsWeek' + date)
+ .select('.kronolithEvent')
+ .invoke('remove');
+ $('kronolithAllDay' + date)
+ .select('.kronolithEvent')
+ .invoke('remove');
+ }
+ break;
+
+ case 'month':
+ $('kronolithMonthDay' + date)
+ .select('div[calendar=' + calendar + ']')
+ .invoke('remove');
+ break;
+
+ case 'year':
+ title = '';
+ busy = false;
+ }
+
+ this._getCacheForDate(date).sortBy(this._sortEvents).each(function(event) {
+ switch (view) {
+ case 'month':
+ case 'agenda':
+ if (calendar != event.value.calendar) {
+ return;
+ }
+ break;
+
+ case 'year':
+ if (event.value.al) {
+ title += Kronolith.text.allday;
+ } else {
+ title += event.value.start.toString('t') + '-' + event.value.end.toString('t');
+ }
+ title += ': ' + event.value.t;
+ if (event.value.x == Kronolith.conf.status.tentative ||
+ event.value.x == Kronolith.conf.status.confirmed) {
+ busy = true;
+ }
+ title += '<br />';
+ return;
+ }
+ this._insertEvent(event, date, view);
+ }, this);
+
+ if (view == 'year') {
+ td = $('kronolithYearTable' + day.getMonth()).down('td[date=' + date + ']');
+ td.className = '';
+ if (title) {
+ td.writeAttribute('title', title).addClassName('kronolithHasEvents');
+ if (td.readAttribute('nicetitle')) {
+ Horde_ToolTips.detach(td);
+ }
+ Horde_ToolTips.attach(td);
+ if (busy) {
+ td.addClassName('kronolithIsBusy');
+ }
+ }
+ }
+
+ day.next().day();
+ }
+ // Workaround Firebug bug.
+ Prototype.emptyFunction();
+ },
+
+ /**
+ * Creates the DOM node for an event bubble and inserts it into the view.
+ *
+ * @param object event A Hash member with the event to insert.
+ * @param string date The day to update.
+ * @param string view The view to update.
+ */
+ _insertEvent: function(event, date, view)
+ {
+ event.value.nodeId = 'kronolithEvent' + view + event.value.calendar + date + event.key;
+
+ _createElement = function(event) {
+ return new Element('DIV', {
+ 'id': event.value.nodeId,
+ 'calendar': event.value.calendar,
+ 'eventid' : event.key,
+ 'class': 'kronolithEvent'
+ });
+ };
+
+ switch (view) {
+ case 'day':
+ case 'week':
+ var storage = view + 'Sizes',
+ div = _createElement(event),
+ style = { 'backgroundColor': event.value.bg,
+ 'color': event.value.fg };
+
+ this._calculateRowSizes(storage, view == 'day' ? 'kronolithViewDay' : 'kronolithViewWeek');
+
+ if (event.value.al) {
+ if (view == 'day') {
+ $('kronolithViewDayBody').down('td').next('td').insert(div.setStyle(style));
+ } else {
+ $('kronolithAllDay' + date).insert(div.setStyle(style));
+ }
+ break;
+ }
+
+ var midnight = this.parseDate(date),
+ innerDiv = new Element('DIV', { 'class': 'kronolithEventInfo' }),
+ draggerTop = new Element('DIV', { 'id': event.value.nodeId + 'top', 'class': 'kronolithDragger kronolithDraggerTop' }).setStyle(style),
+ draggerBottom = new Element('DIV', { 'id': event.value.nodeId + 'bottom', 'class': 'kronolithDragger kronolithDraggerBottom' }).setStyle(style);
+
+ div.setStyle({
+ 'top': ((midnight.getElapsed(event.value.start) / 60000 | 0) * this[storage].height / 60 + this[storage].offset | 0) + 'px',
+ 'height': ((event.value.start.getElapsed(event.value.end) / 60000 | 0) * this[storage].height / 60 - this[storage].spacing | 0) + 'px',
+ 'width': '100%'
+ })
+ .insert(innerDiv.setStyle(style))
+ .insert(draggerTop)
+ .insert(draggerBottom);
+ $(view == 'day' ? 'kronolithEventsDay' : 'kronolithEventsWeek' + date).insert(div);
+
+ if (event.value.pe) {
+ div.addClassName('kronolithEditable').setStyle({ 'cursor': 'move' });
+ var minTop = this[storage].allDay + this[storage].spacing,
+ step = this[storage].height / 6,
+ dragTop = draggerTop.cumulativeOffset()[1],
+ dragBottom = draggerBottom.cumulativeOffset()[1],
+ dragBottomHeight = draggerBottom.getHeight(),
+ eventTop = div.cumulativeOffset()[1],
+ maxTop = div.offsetTop + draggerBottom.offsetTop
+ - this[storage].allDay - this[storage].spacing
+ - draggerTop.getHeight()
+ - parseInt(innerDiv.getStyle('lineHeight')),
+ minBottom = div.offsetTop
+ - this[storage].allDay - this[storage].spacing
+ + draggerTop.getHeight() - dragBottomHeight
+ + parseInt(innerDiv.getStyle('lineHeight')),
+ maxBottom = 24 * KronolithCore[storage].height
+ + this[storage].allDay
+ - dragBottomHeight - minTop,
+ divHeight = div.getHeight(),
+ maxDiv = 24 * KronolithCore[storage].height
+ + this[storage].allDay
+ - divHeight - minTop,
+ opts = {
+ 'threshold': 5,
+ 'constraint': 'vertical',
+ 'scroll': 'kronolithBody',
+ 'nodrop': true,
+ 'parentElement': function() {
+ return $(view == 'day' ? 'kronolithEventsDay' : 'kronolithEventsWeek' + date);
+ },
+ 'onStart': function(d, e) {
+ this.addClassName('kronolithSelected');
+ }.bind(div),
+ 'onEnd': function(d, e) {
+ this[0]._onDragEnd(d, this[1], innerDiv, event, midnight, view);
+ }.bind([this, div]),
+ 'onDrag': function(d, e) {
+ var top = d.ghost.cumulativeOffset()[1],
+ draggingTop = d.ghost.hasClassName('kronolithDraggerTop'),
+ offset, height, dates;
+ if (draggingTop) {
+ offset = top - dragTop;
+ height = this[1].offsetHeight - offset;
+ this[1].setStyle({
+ 'top': (this[1].offsetTop + offset) + 'px',
+ });
+ offset = d.ghost.offsetTop - minTop;
+ dragTop = top;
+ } else {
+ offset = top - dragBottom;
+ height = this[1].offsetHeight + offset;
+ offset = this[1].offsetTop - this[0][storage].allDay - this[0][storage].spacing;
+ dragBottom = top;
+ }
+ this[1].setStyle({
+ 'height': height + 'px'
+ });
+ this[0]._calculateEventDates(event.value, storage, step, offset, height);
+ innerDiv.update('(' + event.value.start.toString(Kronolith.conf.time_format) + ' - ' + event.value.end.toString(Kronolith.conf.time_format) + ') ' + event.value.t);
+ }.bind([this, div])
+ };
+
+ opts.snap = function(x, y, elm) {
+ y = Math.max(0, step * (Math.min(maxTop, y - minTop) / step | 0)) + minTop;
+ return [0, y];
+ }
+ new Drag(event.value.nodeId + 'top', opts);
+
+ opts.snap = function(x, y, elm) {
+ y = Math.min(maxBottom, step * (Math.max(minBottom, y - minTop - dragBottomHeight) / step | 0) + dragBottomHeight) + minTop;
+ return [0, y];
+ }
+ new Drag(event.value.nodeId + 'bottom', opts);
+
+ if (view == 'week') {
+ var dates = this.viewDates(midnight, view),
+ eventStart = event.value.start.clone(),
+ eventEnd = event.value.end.clone(),
+ minLeft = $('kronolithEventsWeek' + dates[0].toString('yyyyMMdd')).offsetLeft - $('kronolithEventsWeek' + date).offsetLeft,
+ maxLeft = $('kronolithEventsWeek' + dates[1].toString('yyyyMMdd')).offsetLeft - $('kronolithEventsWeek' + date).offsetLeft,
+ stepX = (maxLeft - minLeft) / 6;
+ }
+ new Drag(div, {
+ 'threshold': 5,
+ 'nodrop': true,
+ 'parentElement': function() { return $(view == 'day' ? 'kronolithEventsDay' : 'kronolithEventsWeek' + date); },
+ 'snap': function(x, y, elm) {
+ if (view == 'week') {
+ x = Math.max(minLeft, stepX * ((Math.min(maxLeft, x) + stepX / 2) / stepX | 0));
+ } else {
+ x = 0;
+ }
+ y = Math.max(0, step * (Math.min(maxDiv, y - minTop) / step | 0)) + minTop;
+ return [x, y];
+ },
+ 'onStart': function(d, e) {
+ this.addClassName('kronolithSelected');
+ this.setStyle({ 'left': 0, 'width': '100%', 'zIndex': 1 });
+ }.bind(div),
+ 'onDrag': function(d, e) {
+ if (Object.isUndefined(d.innerDiv)) {
+ d.innerDiv = d.ghost.select('.kronolithEventInfo')[0];
+ }
+ if (view == 'week') {
+ var offsetX = Math.round(d.ghost.offsetLeft / stepX);
+ this[0]._calculateEventDates(event.value, storage, step, d.ghost.offsetTop - minTop, divHeight, eventStart.clone().addDays(offsetX), eventEnd.clone().addDays(offsetX));
+ } else {
+ this[0]._calculateEventDates(event.value, storage, step, d.ghost.offsetTop - minTop, divHeight);
+ }
+ d.innerDiv.update('(' + event.value.start.toString(Kronolith.conf.time_format) + ' - ' + event.value.end.toString(Kronolith.conf.time_format) + ') ' + event.value.t);
+ this[1].clonePosition(d.ghost);
+ }.bind([this, div]),
+ 'onEnd': function(d, e) {
+ this[0]._onDragEnd(d, this[1], innerDiv, event, midnight, view);
+ }.bind([this, div]),
+ });
+ }
+
+ var column = 1, columns, width, left, conflict = false,
+ pos = this.dayGroups.length, placeFound = false;
+
+ this.dayEvents.each(function(ev) {
+ if (!ev.end.isAfter(event.value.start)) {
+ placeFound = ev;
+ return;
+ }
+
+ if (!conflict) {
+ conflict = ev;
+ for (i = 0; i < this.dayGroups.length; i++) {
+ if (this.dayGroups[i].indexOf(conflict) != -1) {
+ if (this.dayGroups[i].indexOf(placeFound) == -1) {
+ placeFound = false;
+ }
+ break;
+ }
+ }
+ }
+ if (!placeFound) {
+ column++;
+ }
+ }, this);
+ event.value.column = column;
+
+ if (conflict) {
+ for (i = 0; i < this.dayGroups.length; i++) {
+ if (this.dayGroups[i].indexOf(conflict) != -1) {
+ pos = i;
+ break;
+ }
+ }
+ columns = Math.max(conflict.columns, column);
+ } else {
+ columns = column;
+ }
+ if (Object.isUndefined(this.dayGroups[pos])) {
+ this.dayGroups[pos] = [];
+ }
+ this.dayGroups[pos].push(event.value);
+ width = 100 / columns;
+ this.dayGroups[pos].each(function(ev) {
+ ev.columns = columns;
+ $(ev.nodeId).setStyle({ 'width': width + '%', 'left': (width * (ev.column - 1)) + '%' });
+ });
+ this.dayEvents.push(event.value);
+
+ div = innerDiv;
+ break;
+
+ case 'month':
+ var div = _createElement(event)
+ .setStyle({ 'backgroundColor': event.value.bg,
+ 'color': event.value.fg });
+
+ $('kronolithMonthDay' + date).insert(div);
+ if (event.value.pe) {
+ div.setStyle({ 'cursor': 'move' });
+ new Drag('kronolithEventmonth' + event.value.calendar + date + event.key, { threshold: 5, parentElement: function() { return $('kronolithViewMonthBody'); }, snapToParent: true });
+ }
+ break;
+
+ case 'agenda':
+ var div = _createElement(event)
+ .setStyle({ 'backgroundColor': event.value.bg,
+ 'color': event.value.fg });
+ if (!event.value.al) {
+ div.update(new Element('SPAN', { 'class': 'kronolithDate' }).update(event.value.start.toString('t')))
+ .insert(' ')
+ .insert(new Element('SPAN', { 'class': 'kronolithSep' }).update('·'))
+ .insert(' ');
+ }
+ this.createAgendaDay(date);
+ $('kronolithAgendaDay' + date).insert(div);
+ break;
+ }
+
+ this._setEventText(div, event.value)
+ .observe('mouseover', div.addClassName.curry('kronolithSelected'))
+ .observe('mouseout', div.removeClassName.curry('kronolithSelected'));
+ },
+
+ _setEventText: function(div, event)
+ {
+ if (event.ic) {
+ div.insert(new Element('IMG', { 'src': event.ic }));
+ }
+ div.insert(event.t);
+ if (event.a) {
+ div.insert(' ')
+ .insert(new Element('IMG', { 'src': Kronolith.conf.URI_IMG + 'alarm-' + event.fg.substr(1) + '.png', 'title': Kronolith.text.alarm + ' ' + event.a }));
+ }
+ if (event.r) {
+ div.insert(' ')
+ .insert(new Element('IMG', { 'src': Kronolith.conf.URI_IMG + 'recur-' + event.fg.substr(1) + '.png', 'title': Kronolith.text.recur[event.r] }));
+ }
+ return div;
+ },
+
+ _removeEvent: function(event, calendar)
+ {
+ this._deleteCache(event, calendar);
+ $('kronolithBody').select('div[calendar=' + calendar + '][eventid=' + event + ']').invoke('remove');
+ },
+
+ /**
+ * Calculates the event's start and end dates based on some drag and drop
+ * information.
+ */
+ _calculateEventDates: function(event, storage, step, offset, height, start, end)
+ {
+ if (!Object.isUndefined(start)) {
+ event.start = start;
+ event.end = end;
+ }
+ event.start.set({
+ hour: offset / this[storage].height | 0,
+ minute: Math.round(offset % this[storage].height / step * 10)
+ });
+ event.end.set({
+ hour: (offset + height + this[storage].spacing) / this[storage].height | 0,
+ minute: Math.round((offset + height + this[storage].spacing) % this[storage].height / step * 10)
+ });
+ },
+
+ /**
+ * Called as the event handler after dragging/resizing a day/week event.
+ */
+ _onDragEnd: function(drag, div, innerDiv, event, date, view)
+ {
+ var dates = this.viewDates(date, view),
+ start = dates[0].toString('yyyyMMdd'),
+ end = dates[1].toString('yyyyMMdd');
+ div.removeClassName('kronolithSelected');
+ this._setEventText(innerDiv, event.value);
+ drag.destroy();
+ this.startLoading(event.value.calendar, start, end);
+ this.doAction(
+ 'UpdateEvent',
+ { 'cal': event.value.calendar,
+ 'id': event.key,
+ 'view': view,
+ 'view_start': start,
+ 'view_end': end,
+ 'att': $H({
+ start: event.value.start,
+ end: event.value.end,
+ }).toJSON()
+ },
+ function(r) {
+ if (r.response.events) {
+ this._removeEvent(event.key, event.value.calendar);
+ }
+ this._loadEventsCallback(r);
+ }.bind(this));
+ },
+
+ /**
+ * Loads tasks, either from cache or from the server.
+ *
+ * @param integer taskType The tasks type, (1 = all tasks,
+ * 0 = incomplete tasks, 2 = complete tasks,
+ * 3 = future tasks, 4 = future and incomplete
+ * tasks)
+ * @param Array tasksLists The lists from where to obtain the tasks
+ */
+ _loadTasks: function(taskType, taskLists)
+ {
+ if (Object.isUndefined(taskLists)) {
+ taskLists = [];
+ // FIXME: Temporary hack to get the tasklists
+ $H(Kronolith.conf.calendars.external).each(function(cal) {
+ if (cal.value.api = 'Tasks' && cal.value.show)
+ {
+ taskLists.push(cal.key.substring(6));
+ }
+ });
+ }
+
+ taskLists.each(function(taskList) {
+ var list = this.tcache.get(taskList);
+ if (!Object.isUndefined(list)) {
+ this._insertTasks(taskType, taskList);
+ return;
+ }
+
+ this.startLoading('tasks:' + taskList, taskType, '');
+ this._storeTasksCache($H(), taskList);
+ this.doAction('ListTasks', { 'taskType': taskType, 'list': taskList }, this._loadTasksCallback.bind(this));
+ }, this);
+ },
+
+ /**
+ * Callback method for inserting tasks in the current view.
+ *
+ * @param object r The ajax response object.
+ */
+ _loadTasksCallback: function(r)
+ {
+ // Hide spinner.
+ this.loading--;
+ if (!this.loading) {
+ $('kronolithLoading').hide();
+ }
+
+ this._storeTasksCache(r.response.tasks || {}, r.response.taskList);
+
+ // Check if this is the still the result of the most current request.
+ if (this.view != 'tasks' ||
+ this.eventsLoading['tasks:' + r.response.taskList] != r.response.taskType) {
+ return;
+ }
+ this._insertTasks(r.response.taskType, r.response.taskList);
+ },
+
+ /**
+ * Reads tasks from the cache and inserts them into the view.
+ *
+ * @param integer taskType The tasks type, (1 = all tasks,
+ * 0 = incomplete tasks, 2 = complete tasks,
+ * 3 = future tasks, 4 = future and incomplete
+ * tasks)
+ * @param string tasksList The task list to be drawn
+ */
+ _insertTasks: function(taskType, taskList)
+ {
+ $('kronolithViewTasksBody').select('tr[taskList=' + taskList + ']').invoke('remove');
+ var tasks = this.tcache.get(taskList);
+ $H(tasks).each(function(task) {
+ // TODO: Check for the taskType
+ this._insertTask(task);
+ }, this);
+ },
+
+ /**
+ * Creates the DOM node for a task and inserts it into the view.
+ *
+ * @param object task A Hash with the task to insert
+ */
+ _insertTask: function(task)
+ {
+ var body = $('kronolithViewTasksBody'),
+ row = $('kronolithTasksTemplate').cloneNode(true),
+ col = row.down(),
+ div = col.down();
+
+ row.removeAttribute('id');
+ row.writeAttribute('taskList', task.value.l);
+ row.writeAttribute('taskId', task.key);
+ col.addClassName('kronolithTask' + (task.value.cp != 0 ? 'Completed' : ''));
+ col.insert(task.value.n);
+ if (!Object.isUndefined(task.value.du)) {
+ var date = Date.parse(task.value.du),
+ now = new Date();
+ if (!now.isBefore(date)) {
+ col.addClassName('kronolithTaskDue');
+ col.insert(new Element('SPAN', { 'class': 'kronolithSep' }).update(' · '));
+ col.insert(new Element('SPAN', { 'class': 'kronolithDate' }).update(date.toString(Kronolith.conf.date_format)));
+ }
+ }
+
+ if (!Object.isUndefined(task.value.sd)) {
+ col.insert(new Element('SPAN', { 'class': 'kronolithSep' }).update(' · '));
+ col.insert(new Element('SPAN', { 'class': 'kronolithInfo' }).update(task.value.sd));
+ }
+
+ row.insert(col.show());
+ this._insertTaskPosition(row, task);
+ },
+
+ /**
+ * Inserts the task row in the correct position.
+ *
+ * @param Element newRow The new row to be inserted.
+ * @param object newTask A Hash with the task being added.
+ */
+ _insertTaskPosition: function(newRow, newTask)
+ {
+ var rows = $('kronolithViewTasksBody').select('tr');
+ // The first row is a template one, so must be ignored
+ for (var i = 1; i < rows.length; i++) {
+ var rowTaskList = rows[i].readAttribute('taskList');
+ var rowTaskId = rows[i].readAttribute('taskId');
+ var rowTask = this.tcache.get(rowTaskList).get(rowTaskId);
+
+ // TODO: Assuming that tasks of the same tasklist are already in
+ // order
+ if (rowTaskList == newTask.value.l) {
+ continue;
+ }
+
+ if (Object.isUndefined(rowTask)) {
+ // TODO: Throw error
+ return;
+ }
+ if (!this._isTaskAfter(newTask.value, rowTask)) {
+ break;
+ }
+ }
+ rows[--i].insert({ 'after': newRow.show() });
+ },
+
+ /**
+ * Analyzes which task should be drawn first.
+ *
+ * TODO: Very incomplete, only a dummy version
+ */
+ _isTaskAfter: function(taskA, taskB)
+ {
+ // TODO: Make all ordering system
+ return (taskA.pr >= taskB.pr);
+ },
+
+ /**
+ * Completes/uncompletes a task.
+ *
+ * @param string taskList The task list to which the tasks belongs
+ * @param string taskId The id of the task
+ */
+ _toggleCompletion: function(taskList, taskId)
+ {
+ var task = this.tcache.get(taskList).get(taskId);
+ if (Object.isUndefined(task)) {
+ this._toggleCompletionClass(taskId);
+ // TODO: Show some message?
+ return;
+ }
+ // Update the cache
+ task.cp = (task.cp == "1") ? "0": "1";
+ },
+
+ /**
+ * Toggles the CSS class to show that a tasks is completed/uncompleted.
+ *
+ * @param string taskId The id of the task
+ */
+ _toggleCompletionClass: function(taskId)
+ {
+ var row = $(taskId);
+ if (row.length == 0) {
+ // FIXME: Show some error?
+ return;
+ }
+ var col = row.down('td.kronolithTaskCol', 0), div = col.down('div.kronolithTaskCheckbox', 0);
+
+ col.toggleClassName('kronolithTask');
+ col.toggleClassName('kronolithTaskCompleted');
+ },
+
+ /**
+ * Parses a date attribute string into a Date object.
+ *
+ * For other strings use Date.parse().
+ *
+ * @param string date A yyyyMMdd date string.
+ *
+ * @return Date A date object.
+ */
+ parseDate: function(date)
+ {
+ return new Date(date.substr(0, 4), date.substr(4, 2) - 1, date.substr(6, 2));
+ },
+
+ /**
+ * Calculates first and last days being displayed.
+ *
+ * @var Date date The date of the view.
+ * @var string view A view name.
+ *
+ * @return array Array with first and last day of the view.
+ */
+ viewDates: function(date, view)
+ {
+ var start = date.clone(), end = date.clone();
+
+ switch (view) {
+ case 'week':
+ start.moveToBeginOfWeek(Kronolith.conf.week_start);
+ end.moveToEndOfWeek(Kronolith.conf.week_start);
+ break;
+ case 'month':
+ start.setDate(1);
+ start.moveToBeginOfWeek(Kronolith.conf.week_start);
+ end.moveToLastDayOfMonth();
+ end.moveToEndOfWeek(Kronolith.conf.week_start);
+ break;
+ case 'year':
+ start.setDate(1);
+ start.setMonth(0);
+ end.setMonth(11);
+ end.moveToLastDayOfMonth();
+ break;
+ case 'agenda':
+ end.add(6).days();
+ break;
+ }
+
+ return [start, end];
+ },
+
+ /**
+ * Stores a set of events in the cache.
+ *
+ * For dates in the specified date ranges that don't contain any events,
+ * empty cache entries are created so that those dates aren't re-fetched
+ * each time.
+ *
+ * @param object events A list of calendars and events as returned from
+ * an ajax request.
+ * @param string calendar A calendar string or array.
+ * @param string dates A date range in the format yyyymmddyyyymmdd as
+ * used in the ajax response signature.
+ */
+ _storeCache: function(events, calendar, dates)
+ {
+ if (Object.isString(calendar)) {
+ calendar = calendar.split('|');
+ }
+
+ // Create cache entry for the calendar.
+ if (!this.ecache.get(calendar[0])) {
+ this.ecache.set(calendar[0], $H());
+ }
+ if (!this.ecache.get(calendar[0]).get(calendar[1])) {
+ this.ecache.get(calendar[0]).set(calendar[1], $H());
+ }
+ var calHash = this.ecache.get(calendar[0]).get(calendar[1]);
+
+ // Create empty cache entries for all dates.
+ if (typeof dates != 'undefined') {
+ var day = dates[0].clone(), date;
+ while (!day.isAfter(dates[1])) {
+ date = day.dateString();
+ if (!calHash.get(date)) {
+ calHash.set(date, $H());
+ }
+ day.add(1).day();
+ }
+ }
+
+ var cal = calendar.join('|');
+ $H(events).each(function(date) {
+ // Store calendar string and other useful information in event
+ // objects.
+ $H(date.value).each(function(event) {
+ event.value.calendar = cal;
+ event.value.start = Date.parse(event.value.s);
+ event.value.end = Date.parse(event.value.e);
+ event.value.sort = event.value.start.toString('HHmmss')
+ + (240000 - parseInt(event.value.end.toString('HHmmss'))).toPaddedString(6);
+ });
+
+ // Store events in cache.
+ calHash.set(date.key, calHash.get(date.key).merge(date.value));
+ });
+ },
+
+ /**
+ * Stores a set of tasks in the cache.
+ *
+ * @param Hash tasks The tasks to be stored
+ * @param string taskList The task list to which the tasks belong
+ */
+ _storeTasksCache: function(tasks, taskList)
+ {
+ if (!this.tcache.get(taskList)) {
+ this.tcache.set(taskList, $H());
+ }
+
+ var taskHash = this.tcache.get(taskList);
+
+ $H(tasks).each(function(task) {
+ taskHash.set(task.key, task.value);
+ });
+ },
+
+ /**
+ * Deletes an event from the cache.
+ *
+ * @param string event An event ID.
+ * @param string calendar A calendar string or array.
+ */
+ _deleteCache: function(event, calendar)
+ {
+ if (Object.isString(calendar)) {
+ calendar = calendar.split('|');
+ }
+ if (!this.ecache.get(calendar[0]) ||
+ !this.ecache.get(calendar[0]).get(calendar[1])) {
+ return;
+ }
+ this.ecache.get(calendar[0]).get(calendar[1]).each(function(day) {
+ delete day.value[event];
+ });
+ },
+
+ /**
+ * Return all events for a single day from all displayed calendars merged
+ * into a single hash.
+ *
+ * @param string date A yyyymmdd date string.
+ *
+ * @return Hash An event hash which event ids as keys and event objects as
+ * values.
+ */
+ _getCacheForDate: function(date)
+ {
+ var events = $H();
+ this.ecache.each(function(type) {
+ type.value.each(function(cal) {
+ if (!Kronolith.conf.calendars[type.key][cal.key].show) {
+ return;
+ }
+ events = events.merge(cal.value.get(date));
+ });
+ });
+ return events;
+ },
+
+ /**
+ * Helper method for Enumerable.sortBy to sort events first by start time,
+ * second by end time reversed.
+ *
+ * @param Hash event A hash entry with the event object as the value.
+ *
+ * @return string A comparable string.
+ */
+ _sortEvents: function(event)
+ {
+ return event.value.sort;
+ },
+
+ _addHistory: function(loc, data)
+ {
+ if (Horde.dhtmlHistory.getCurrentLocation() != loc) {
+ Horde.dhtmlHistory.add(loc, data);
+ }
+ },
+
+ iframeContent: function(name, loc)
+ {
+ if (name === null) {
+ name = loc;
+ }
+
+ var container = $('dimpmain_portal'), iframe;
+ if (!container) {
+ this.showNotifications([ { type: 'horde.error', message: 'Bad portal!' } ]);
+ return;
+ }
+
+ iframe = new Element('IFRAME', { id: 'iframe' + name, className: 'iframe', frameBorder: 0, src: loc });
+ this._resizeIE6Iframe(iframe);
+
+ // Hide menu in prefs pages.
+ if (name == 'options') {
+ iframe.observe('load', function() { $('iframeoptions').contentWindow.document.getElementById('menu').style.display = 'none'; });
+ }
+
+ container.insert(iframe);
+ },
+
+ onResize: function(noupdate, nowait)
+ {
+ },
+
+ /* Keydown event handler */
+ keydownHandler: function(e)
+ {
+ var kc = e.keyCode || e.charCode;
+
+ form = e.findElement('FORM');
+ if (form) {
+ switch (kc) {
+ case Event.KEY_RETURN:
+ switch (form.identify()) {
+ case 'kronolithEventForm':
+ this.saveEvent();
+ e.stop();
+ break;
+
+ case 'kronolithSearchForm':
+ this.go('search:' + $F('kronolithSearchContext') + ':' + $F('kronolithSearchTerm'))
+ e.stop();
+ break;
+ }
+ break;
+ }
+ return;
+ }
+
+ switch (kc) {
+ case Event.KEY_ESC:
+ this._closeRedBox();
+ break;
+ }
+ },
+
+ keyupHandler: function(e)
+ {
+ /*
+ if (e.element().readAttribute('id') == 'foo') {
+ }
+ */
+ },
+
+ clickHandler: function(e, dblclick)
+ {
+ if (e.isRightClick()) {
+ return;
+ }
+
+ var elt = e.element(),
+ orig = e.element(),
+ id, tmp, calendar, calendarClass;
+
+ while (Object.isElement(elt)) {
+ id = elt.readAttribute('id');
+
+ switch (id) {
+ case 'kronolithLogo':
+ this.go('portal');
+ e.stop();
+ return;
+
+ case 'id_fullday':
+ this.eventForm.select('.edit_at').each(Element.toggle);
+ e.stop();
+ return;
+
+ case 'kronolithNewEvent':
+ this.go('event');
+ e.stop();
+ return;
+
+ case 'kronolithEventSave':
+ this.saveEvent();
+ e.stop();
+ return;
+
+ case 'kronolithEventDelete':
+ var cal = $F('kronolithEventCalendar'),
+ eventid = $F('kronolithEventId');
+ this.doAction('DeleteEvent',
+ { 'cal': cal, 'id': eventid },
+ function(r) {
+ if (r.response.deleted) {
+ this._removeEvent(eventid, cal);
+ } else {
+ $('kronolithBody').select('div[calendar=' + cal + '][eventid=' + eventid + ']').invoke('toggle');
+ }
+ }.bind(this));
+ $('kronolithBody').select('div[calendar=' + cal + '][eventid=' + eventid + ']').invoke('hide');
+ this._closeRedBox();
+ e.stop();
+ return;
+
+ case 'kronolithEventCancel':
+ this._closeRedBox();
+ e.stop();
+ return;
+
+ case 'kronolithNavDay':
+ case 'kronolithNavWeek':
+ case 'kronolithNavMonth':
+ case 'kronolithNavYear':
+ case 'kronolithNavTasks':
+ case 'kronolithNavAgenda':
+ this.go(id.substring(12).toLowerCase() + ':' + this.date.dateString());
+ e.stop();
+ return;
+
+ case 'kronolithMinicalDate':
+ this.go('month:' + orig.readAttribute('date'));
+ e.stop();
+ return;
+
+ case 'kronolithMinical':
+ if (orig.id == 'kronolithMinicalPrev') {
+ var date = this.parseDate($('kronolithMinicalDate').readAttribute('date'));
+ date.previous().month();
+ this.updateMinical(date);
+ e.stop();
+ return;
+ }
+ if (orig.id == 'kronolithMinicalNext') {
+ var date = this.parseDate($('kronolithMinicalDate').readAttribute('date'));
+ date.next().month();
+ this.updateMinical(date);
+ e.stop();
+ return;
+ }
+
+ var tmp = orig;
+ if (tmp.tagName != 'td') {
+ tmp.up('td');
+ }
+ if (tmp) {
+ if (tmp.readAttribute('weekdate') &&
+ tmp.hasClassName('kronolithMinicalWeek')) {
+ this.go('week:' + tmp.readAttribute('weekdate'));
+ } else if (tmp.readAttribute('date') &&
+ !tmp.hasClassName('empty')) {
+ this.go('day:' + tmp.readAttribute('date'));
+ }
+ }
+ e.stop();
+ return;
+
+ case 'kronolithViewMonth':
+ if (orig.hasClassName('kronolithFirstCol')) {
+ var date = orig.readAttribute('date');
+ if (date) {
+ this.go('week:' + date);
+ e.stop();
+ return;
+ }
+ } else if (orig.hasClassName('kronolithDay')) {
+ var date = orig.readAttribute('date');
+ if (date) {
+ this.go('day:' + date);
+ e.stop();
+ return;
+ }
+ }
+ e.stop();
+ return;
+
+ case 'kronolithViewYear':
+ var tmp = orig;
+ if (tmp.tagName != 'td') {
+ tmp.up('td');
+ }
+ if (tmp) {
+ if (tmp.readAttribute('weekdate') &&
+ tmp.hasClassName('kronolithMinicalWeek')) {
+ this.go('week:' + tmp.readAttribute('weekdate'));
+ } else if (tmp.hasClassName('kronolithMinicalDate')) {
+ this.go('month:' + tmp.readAttribute('date'));
+ } else if (tmp.readAttribute('date') &&
+ !tmp.hasClassName('empty')) {
+ this.go('day:' + tmp.readAttribute('date'));
+ }
+ }
+ e.stop();
+ return;
+
+ case 'kronolithViewAgenda':
+ var tmp = orig;
+ if (tmp.tagName != 'td') {
+ tmp.up('td');
+ }
+ if (tmp && tmp.readAttribute('date')) {
+ this.go('day:' + tmp.readAttribute('date'));
+ }
+ e.stop();
+ return;
+
+ case 'kronolithSearchButton':
+ this.go('search:' + $F('kronolithSearchContext') + ':' + $F('kronolithSearchTerm'))
+ break;
+
+ case 'alertsloglink':
+ tmp = $('alertsloglink').down('A');
+ if (this.Growler.toggleLog()) {
+ tmp.update(DIMP.text.hidealog);
+ } else {
+ tmp.update(DIMP.text.showalog);
+ }
+ break;
+ }
+
+ // Caution, this only works if the element has definitely only a
+ // single CSS class.
+ switch (elt.className) {
+ case 'kronolithGotoToday':
+ this.go(this.view + ':' + new Date().dateString());
+ e.stop();
+ return;
+
+ case 'kronolithPrev':
+ case 'kronolithNext':
+ var newDate = this.date.clone(),
+ offset = elt.className == 'kronolithPrev' ? -1 : 1;
+ switch (this.view) {
+ case 'day':
+ case 'agenda':
+ newDate.add(offset).day();
+ break;
+ case 'week':
+ newDate.add(offset).week();
+ break;
+ case 'month':
+ newDate.add(offset).month();
+ break;
+ case 'year':
+ newDate.add(offset).year();
+ break;
+ }
+ this.go(this.view + ':' + newDate.dateString());
+ e.stop();
+ return;
+
+ case 'kronolithAddEvent':
+ this.go('event:' + elt.readAttribute('date'));
+ e.stop();
+ return;
+
+ case 'kronolithEventTag':
+ $('kronolithEventTags').autocompleter.addNewItemNode(elt.getText());
+ e.stop();
+ return;
+ }
+
+ if (elt.hasClassName('kronolithEvent')) {
+ this.go('event:' + elt.readAttribute('calendar') + ':' + elt.readAttribute('eventid'));
+ e.stop();
+ return;
+ } else if (elt.hasClassName('kronolithWeekDay')) {
+ this.go('day:' + elt.readAttribute('date'));
+ e.stop();
+ return;
+ } else if (elt.hasClassName('kronolithTaskCheckbox')) {
+ var taskId = elt.up('tr.kronolithTaskRow', 0).readAttribute('id'),
+ taskList = elt.up('tr.kronolithTaskRow', 0).readAttribute('tasklist');
+ this._toggleCompletionClass(taskId);
+ this.doAction('ToggleCompletion',
+ { taskList: taskList, taskType: this.taskType, taskId: taskId },
+ function(r) {
+ if (r.response.toggled) {
+ this._toggleCompletion(taskList, taskId);
+ } else {
+ // Check if this is the still the result
+ // of the most current request.
+ if (this.view != 'tasks' || this.taskType != r.response.taskType) {
+ return;
+ }
+ this._toggleCompletionClass(taskId);
+ }
+ }.bind(this));
+ e.stop();
+ return;
+ }
+
+ calClass = elt.readAttribute('calendarclass');
+ if (calClass) {
+ var calendar = elt.readAttribute('calendar');
+ Kronolith.conf.calendars[calClass][calendar].show = !Kronolith.conf.calendars[calClass][calendar].show;
+ if (this.view == 'year' ||
+ typeof this.ecache.get(calClass) == 'undefined' ||
+ typeof this.ecache.get(calClass).get(calendar) == 'undefined') {
+ var dates = this.viewDates(this.date, this.view);
+ this._loadEvents(dates[0], dates[1], this.view, [[calClass, calendar]]);
+ } else {
+ $('kronolithBody').select('div[calendar=' + calClass + '|' + calendar + ']').invoke('toggle');
+ }
+ elt.toggleClassName('kronolithCalOn');
+ elt.toggleClassName('kronolithCalOff');
+ if (calClass == 'remote' || calClass == 'external') {
+ if (calClass == 'external' && calendar.startsWith('tasks/')) {
+ var taskList = calendar.substr(6);
+ if (typeof this.tcache.get(taskList) == 'undefined' &&
+ this.view == 'tasks') {
+ this._loadTasks(this.taskType,[taskList]);
+ } else {
+ $('kronolithViewTasksBody').select('tr[taskList=' + taskList + ']').invoke('toggle');
+ }
+ }
+ calendar = calClass + '_' + calendar;
+ }
+ this.doAction('SaveCalPref', { toggle_calendar: calendar });
+ }
+
+ elt = elt.up();
+ }
+ // Workaround Firebug bug.
+ Prototype.emptyFunction();
+ },
+
+ mouseHandler: function(e, type)
+ {
+ /*
+ var elt = e.element();
+
+ switch (type) {
+ case 'over':
+ if (DragDrop.Drags.drag && elt.hasClassName('exp')) {
+ this._toggleSubFolder(elt.up(), 'exp');
+ }
+ break;
+ }
+ */
+ },
+
+ editEvent: function(calendar, id, date)
+ {
+ if (Object.isUndefined($('kronolithEventTags').autocompleter)) {
+ this.editEvent.bind(this, calendar, id, date).defer();
+ return;
+ }
+
+ RedBox.onDisplay = function() {
+ try {
+ $('kronolithEventForm').focusFirstElement();
+ } catch(e) {}
+ RedBox.onDisplay = null;
+ };
+
+ $('kronolithEventTags').autocompleter.init();
+ $('kronolithEventForm').enable();
+ $('kronolithEventForm').reset();
+ this.doAction('ListTopTags', {}, this._topTags);
+ if (id) {
+ RedBox.loading();
+ this.doAction('GetEvent', { 'cal': calendar, 'id': id }, this._editEvent.bind(this));
+ } else {
+ var d = date ? this.parseDate(date) : new Date();
+ $('kronolithEventId').value = '';
+ $('kronolithEventCalendar').value = Kronolith.conf.default_calendar;
+ $('kronolithEventDelete').hide();
+ $('kronolithEventStartDate').value = d.toString(Kronolith.conf.date_format);
+ $('kronolithEventStartTime').value = d.toString(Kronolith.conf.time_format);
+ d.add(1).hour();
+ $('kronolithEventEndDate').value = d.toString(Kronolith.conf.date_format);
+ $('kronolithEventEndTime').value = d.toString(Kronolith.conf.time_format);
+ RedBox.showHtml($('kronolithEventDialog').show());
+ this.eventForm = RedBox.getWindowContents();
+ }
+ },
+
+ saveEvent: function()
+ {
+ var cal = $F('kronolithEventCalendar'),
+ eventid = $F('kronolithEventId'),
+ viewDates = this.viewDates(this.date, this.view),
+ start = viewDates[0].dateString(),
+ end = viewDates[1].dateString();
+ this.startLoading(cal, start, end);
+ this.doAction('SaveEvent',
+ $H($('kronolithEventForm').serialize({ 'hash': true }))
+ .merge({
+ 'view': this.view,
+ 'view_start': start,
+ 'view_end': end
+ }),
+ function(r) {
+ if (r.response.events && eventid) {
+ this._removeEvent(eventid, cal);
+ }
+ this._loadEventsCallback(r);
+ this._closeRedBox();
+ }.bind(this));
+ },
+
+ _topTags: function(r)
+ {
+ if (!r.response.tags) {
+ $('kronolithEventTopTags').update();
+ return;
+ }
+ t = new Element('div', {});
+ r.response.tags.each(function(tag) {
+ t.insert(new Element('span', { 'class': 'kronolithEventTag' }).update(tag));
+ });
+ $('kronolithEventTopTags').update(t);
+ return;
+ },
+
+ /**
+ * Callback method for showing event forms.
+ *
+ * @param object r The ajax response object.
+ */
+ _editEvent: function(r)
+ {
+ if (!r.response.event) {
+ RedBox.close();
+ return;
+ }
+
+ var ev = r.response.event;
+ $('kronolithEventId').value = ev.id;
+ $('kronolithEventCalendar').value = ev.ty + '|' + ev.c;
+ $('kronolithEventTitle').value = ev.t;
+ $('kronolithEventLocation').value = ev.l;
+ $('kronolithEventAllday').checked = ev.al;
+ $('kronolithEventStartDate').value = ev.sd
+ $('kronolithEventStartTime').value = ev.st;
+ $('kronolithEventEndDate').value = ev.ed;
+ $('kronolithEventEndTime').value = ev.et;
+ $('kronolithEventTags').autocompleter.init(ev.tg);
+ if (ev.r) {
+ // @todo: refine
+ $A($('kronolithEventRecurrence').options).find(function(option) {
+ return option.value == ev.r || option.value == -1;
+ }).selected = true;
+ }
+ if (ev.pe) {
+ $('kronolithEventSave').show();
+ $('kronolithEventForm').enable();
+ } else {
+ $('kronolithEventSave').hide();
+ $('kronolithEventForm').disable();
+ $('kronolithEventCancel').enable();
+ }
+ if (ev.pd) {
+ $('kronolithEventDelete').show();
+ } else {
+ $('kronolithEventDelete').hide();
+ }
+
+ RedBox.showHtml($('kronolithEventDialog').show());
+ this.eventForm = RedBox.getWindowContents();
+ },
+
+ _closeRedBox: function()
+ {
+ RedBox.close();
+ this.eventForm = null;
+ },
+
+ /* Onload function. */
+ onDomLoad: function()
+ {
+ if (typeof ContextSensitive != 'undefined') {
+ this.DMenu = new ContextSensitive({ onClick: this.contextOnClick, onShow: this.contextOnShow });
+ }
+
+ document.observe('keydown', KronolithCore.keydownHandler.bindAsEventListener(KronolithCore));
+ document.observe('keyup', KronolithCore.keyupHandler.bindAsEventListener(KronolithCore));
+ document.observe('click', KronolithCore.clickHandler.bindAsEventListener(KronolithCore));
+ document.observe('dblclick', KronolithCore.clickHandler.bindAsEventListener(KronolithCore, true));
+ document.observe('mouseover', KronolithCore.mouseHandler.bindAsEventListener(KronolithCore, 'over'));
+
+ if (Horde.dhtmlHistory.initialize()) {
+ Horde.dhtmlHistory.addListener(this.go.bind(this));
+ }
+
+ this.updateCalendarList();
+
+ /* Initialize the starting page if necessary. addListener() will have
+ * already fired if there is a current location so only do a go()
+ * call if there is no current location. */
+ if (!Horde.dhtmlHistory.getCurrentLocation()) {
+ this.go(Kronolith.conf.login_view);
+ }
+
+ $('kronolithMenu').select('div.kronolithCalendars div').each(function(s) {
+ s.observe('mouseover', s.addClassName.curry('kronolithCalOver'));
+ s.observe('mouseout', s.removeClassName.curry('kronolithCalOver'));
+ });
+
+ /* Add Growler notifications. */
+ this.Growler = new Growler({
+ location: 'br',
+ log: true,
+ noalerts: Kronolith.text.noalerts
+ });
+
+ if (Kronolith.conf.is_ie6) {
+ /* Disable text selection in preview pane for IE 6. */
+ document.observe('selectstart', Event.stop);
+
+ /* Since IE 6 doesn't support hover over non-links, use javascript
+ * events to replicate mouseover CSS behavior. */
+ $('foobar').compact().invoke('select', 'LI').flatten().compact().each(function(e) {
+ e.observe('mouseover', e.addClassName.curry('over')).observe('mouseout', e.removeClassName.curry('over'));
+ });
+ }
+ },
+
+ toggleCalendar: function(elm)
+ {
+ elm.toggleClassName('on');
+ },
+
+ // By default, no context onShow action
+ contextOnShow: Prototype.emptyFunction,
+
+ // By default, no context onClick action
+ contextOnClick: Prototype.emptyFunction
+
+};
+
+/* Initialize global event handlers. */
+document.observe('dom:loaded', KronolithCore.onDomLoad.bind(KronolithCore));
+Event.observe(window, 'resize', KronolithCore.onResize.bind(KronolithCore));
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "lt-LT",
+ englishName: "Lithuanian (Lithuania)",
+ nativeName: "lietuvių (Lietuva)",
+
+ /* Day Name Strings */
+ dayNames: ["sekmadienis", "pirmadienis", "antradienis", "trečiadienis", "ketvirtadienis", "penktadienis", "šeštadienis"],
+ abbreviatedDayNames: ["Sk", "Pr", "An", "Tr", "Kt", "Pn", "Št"],
+ shortestDayNames: ["S", "P", "A", "T", "K", "Pn", "Š"],
+ firstLetterDayNames: ["S", "P", "A", "T", "K", "P", "Š"],
+
+ /* Month Name Strings */
+ monthNames: ["sausis", "vasaris", "kovas", "balandis", "gegužė", "birželis", "liepa", "rugpjūtis", "rugsėjis", "spalis", "lapkritis", "gruodis"],
+ abbreviatedMonthNames: ["Sau", "Vas", "Kov", "Bal", "Geg", "Bir", "Lie", "Rgp", "Rgs", "Spl", "Lap", "Grd"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy.MM.dd",
+ longDate: "yyyy 'm.' MMMM d 'd.'",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "yyyy 'm.' MMMM d 'd.' HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM d 'd.'",
+ yearMonth: "yyyy 'm.' MMMM"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^sau(sis)?/i,
+ feb: /^vas(aris)?/i,
+ mar: /^kov(as)?/i,
+ apr: /^bal(andis)?/i,
+ may: /^geg(užė)?/i,
+ jun: /^bir(želis)?/i,
+ jul: /^lie(pa)?/i,
+ aug: /^rugpjūtis/i,
+ sep: /^rugsėjis/i,
+ oct: /^spalis/i,
+ nov: /^lap(kritis)?/i,
+ dec: /^gruodis/i,
+
+ sun: /^s(k(kmadienis)?)?/i,
+ mon: /^p(r(rmadienis)?)?/i,
+ tue: /^a(n(tradienis)?)?/i,
+ wed: /^t(r(ečiadienis)?)?/i,
+ thu: /^k(t(tvirtadienis)?)?/i,
+ fri: /^penktadienis/i,
+ sat: /^š(t(štadienis)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "lv-LV",
+ englishName: "Latvian (Latvia)",
+ nativeName: "latviešu (Latvija)",
+
+ /* Day Name Strings */
+ dayNames: ["svētdiena", "pirmdiena", "otrdiena", "trešdiena", "ceturtdiena", "piektdiena", "sestdiena"],
+ abbreviatedDayNames: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "Se"],
+ shortestDayNames: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "Se"],
+ firstLetterDayNames: ["S", "P", "O", "T", "C", "P", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["janvāris", "februāris", "marts", "aprīlis", "maijs", "jūnijs", "jūlijs", "augusts", "septembris", "oktobris", "novembris", "decembris"],
+ abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jūn", "Jūl", "Aug", "Sep", "Okt", "Nov", "Dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy.MM.dd.",
+ longDate: "dddd, yyyy'. gada 'd. MMMM",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, yyyy'. gada 'd. MMMM H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "yyyy. MMMM"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(vāris)?/i,
+ feb: /^feb(ruāris)?/i,
+ mar: /^mar(ts)?/i,
+ apr: /^apr(īlis)?/i,
+ may: /^mai(js)?/i,
+ jun: /^jūn(ijs)?/i,
+ jul: /^jūl(ijs)?/i,
+ aug: /^aug(usts)?/i,
+ sep: /^sep(tembris)?/i,
+ oct: /^okt(obris)?/i,
+ nov: /^nov(embris)?/i,
+ dec: /^dec(embris)?/i,
+
+ sun: /^svētdiena/i,
+ mon: /^pirmdiena/i,
+ tue: /^otrdiena/i,
+ wed: /^trešdiena/i,
+ thu: /^ceturtdiena/i,
+ fri: /^piektdiena/i,
+ sat: /^sestdiena/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "mk-MK",
+ englishName: "Macedonian (Former Yugoslav Republic of Macedonia)",
+ nativeName: "македонски јазик (Македонија)",
+
+ /* Day Name Strings */
+ dayNames: ["недела", "понеделник", "вторник", "среда", "четврток", "петок", "сабота"],
+ abbreviatedDayNames: ["нед", "пон", "втр", "срд", "чет", "пет", "саб"],
+ shortestDayNames: ["не", "по", "вт", "ср", "че", "пе", "са"],
+ firstLetterDayNames: ["н", "п", "в", "с", "ч", "п", "с"],
+
+ /* Month Name Strings */
+ monthNames: ["јануари", "февруари", "март", "април", "мај", "јуни", "јули", "август", "септември", "октомври", "ноември", "декември"],
+ abbreviatedMonthNames: ["јан", "фев", "мар", "апр", "мај", "јун", "јул", "авг", "сеп", "окт", "ное", "дек"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "dddd, dd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dddd, dd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^јан(уари)?/i,
+ feb: /^фев(руари)?/i,
+ mar: /^мар(т)?/i,
+ apr: /^апр(ил)?/i,
+ may: /^мај/i,
+ jun: /^јун(и)?/i,
+ jul: /^јул(и)?/i,
+ aug: /^авг(уст)?/i,
+ sep: /^сеп(тември)?/i,
+ oct: /^окт(омври)?/i,
+ nov: /^ное(мври)?/i,
+ dec: /^дек(ември)?/i,
+
+ sun: /^не(д(ела)?)?/i,
+ mon: /^по(н(еделник)?)?/i,
+ tue: /^вт(р(рник)?)?/i,
+ wed: /^ср(д(да)?)?/i,
+ thu: /^че(т(врток)?)?/i,
+ fri: /^пе(т(ок)?)?/i,
+ sat: /^са(б(ота)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "nb-NO",
+ englishName: "Norwegian, Bokmål (Norway)",
+ nativeName: "norsk, bokmål (Norge)",
+
+ /* Day Name Strings */
+ dayNames: ["søndag", "mandag", "tirsdag", "onsdag", "torsdag", "fredag", "lørdag"],
+ abbreviatedDayNames: ["sø", "ma", "ti", "on", "to", "fr", "lø"],
+ shortestDayNames: ["sø", "ma", "ti", "on", "to", "fr", "lø"],
+ firstLetterDayNames: ["s", "m", "t", "o", "t", "f", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["januar", "februar", "mars", "april", "mai", "juni", "juli", "august", "september", "oktober", "november", "desember"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "mai", "jun", "jul", "aug", "sep", "okt", "nov", "des"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mar(s)?/i,
+ apr: /^apr(il)?/i,
+ may: /^mai/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^des(ember)?/i,
+
+ sun: /^søndag/i,
+ mon: /^mandag/i,
+ tue: /^tirsdag/i,
+ wed: /^onsdag/i,
+ thu: /^torsdag/i,
+ fri: /^fredag/i,
+ sat: /^lørdag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "nl-NL",
+ englishName: "Dutch (Netherlands)",
+ nativeName: "Nederlands (Nederland)",
+
+ /* Day Name Strings */
+ dayNames: ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"],
+ abbreviatedDayNames: ["zo", "ma", "di", "wo", "do", "vr", "za"],
+ shortestDayNames: ["zo", "ma", "di", "wo", "do", "vr", "za"],
+ firstLetterDayNames: ["z", "m", "d", "w", "d", "v", "z"],
+
+ /* Month Name Strings */
+ monthNames: ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"],
+ abbreviatedMonthNames: ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d-M-yyyy",
+ longDate: "dddd d MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd d MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uari)?/i,
+ feb: /^feb(ruari)?/i,
+ mar: /^maart/i,
+ apr: /^apr(il)?/i,
+ may: /^mei/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ustus)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^zondag/i,
+ mon: /^maandag/i,
+ tue: /^dinsdag/i,
+ wed: /^woensdag/i,
+ thu: /^donderdag/i,
+ fri: /^vrijdag/i,
+ sat: /^zaterdag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "nn-NO",
+ englishName: "Norwegian, Nynorsk (Norway)",
+ nativeName: "norsk, nynorsk (Noreg)",
+
+ /* Day Name Strings */
+ dayNames: ["søndag", "måndag", "tysdag", "onsdag", "torsdag", "fredag", "laurdag"],
+ abbreviatedDayNames: ["sø", "må", "ty", "on", "to", "fr", "la"],
+ shortestDayNames: ["sø", "må", "ty", "on", "to", "fr", "la"],
+ firstLetterDayNames: ["s", "m", "t", "o", "t", "f", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["januar", "februar", "mars", "april", "mai", "juni", "juli", "august", "september", "oktober", "november", "desember"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "mai", "jun", "jul", "aug", "sep", "okt", "nov", "des"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "d. MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mar(s)?/i,
+ apr: /^apr(il)?/i,
+ may: /^mai/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^des(ember)?/i,
+
+ sun: /^søndag/i,
+ mon: /^måndag/i,
+ tue: /^tysdag/i,
+ wed: /^onsdag/i,
+ thu: /^torsdag/i,
+ fri: /^fredag/i,
+ sat: /^laurdag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "pl-PL",
+ englishName: "Polish (Poland)",
+ nativeName: "polski (Polska)",
+
+ /* Day Name Strings */
+ dayNames: ["niedziela", "poniedziałek", "wtorek", "środa", "czwartek", "piątek", "sobota"],
+ abbreviatedDayNames: ["N", "Pn", "Wt", "Śr", "Cz", "Pt", "So"],
+ shortestDayNames: ["N", "Pn", "Wt", "Śr", "Cz", "Pt", "So"],
+ firstLetterDayNames: ["N", "P", "W", "Ś", "C", "P", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["styczeń", "luty", "marzec", "kwiecień", "maj", "czerwiec", "lipiec", "sierpień", "wrzesień", "październik", "listopad", "grudzień"],
+ abbreviatedMonthNames: ["sty", "lut", "mar", "kwi", "maj", "cze", "lip", "sie", "wrz", "paź", "lis", "gru"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy-MM-dd",
+ longDate: "d MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "d MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^sty(czeń)?/i,
+ feb: /^lut(y)?/i,
+ mar: /^mar(zec)?/i,
+ apr: /^kwi(ecień)?/i,
+ may: /^maj/i,
+ jun: /^cze(rwiec)?/i,
+ jul: /^lip(iec)?/i,
+ aug: /^sie(rpień)?/i,
+ sep: /^wrz(esień)?/i,
+ oct: /^paź(dziernik)?/i,
+ nov: /^lis(topad)?/i,
+ dec: /^gru(dzień)?/i,
+
+ sun: /^niedziela/i,
+ mon: /^poniedziałek/i,
+ tue: /^wtorek/i,
+ wed: /^środa/i,
+ thu: /^czwartek/i,
+ fri: /^piątek/i,
+ sat: /^sobota/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "pt-BR",
+ englishName: "Portuguese (Brazil)",
+ nativeName: "Português (Brasil)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "segunda-feira", "terça-feira", "quarta-feira", "quinta-feira", "sexta-feira", "sábado"],
+ abbreviatedDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"],
+ shortestDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"],
+ firstLetterDayNames: ["d", "s", "t", "q", "q", "s", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["janeiro", "fevereiro", "março", "abril", "maio", "junho", "julho", "agosto", "setembro", "outubro", "novembro", "dezembro"],
+ abbreviatedMonthNames: ["jan", "fev", "mar", "abr", "mai", "jun", "jul", "ago", "set", "out", "nov", "dez"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d/M/yyyy",
+ longDate: "dddd, d' de 'MMMM' de 'yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, d' de 'MMMM' de 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd' de 'MMMM",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(eiro)?/i,
+ feb: /^fev(ereiro)?/i,
+ mar: /^mar(ço)?/i,
+ apr: /^abr(il)?/i,
+ may: /^mai(o)?/i,
+ jun: /^jun(ho)?/i,
+ jul: /^jul(ho)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^set(embro)?/i,
+ oct: /^out(ubro)?/i,
+ nov: /^nov(embro)?/i,
+ dec: /^dez(embro)?/i,
+
+ sun: /^domingo/i,
+ mon: /^segunda-feira/i,
+ tue: /^terça-feira/i,
+ wed: /^quarta-feira/i,
+ thu: /^quinta-feira/i,
+ fri: /^sexta-feira/i,
+ sat: /^sábado/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "pt-PT",
+ englishName: "Portuguese (Portugal)",
+ nativeName: "português (Portugal)",
+
+ /* Day Name Strings */
+ dayNames: ["domingo", "segunda-feira", "terça-feira", "quarta-feira", "quinta-feira", "sexta-feira", "sábado"],
+ abbreviatedDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"],
+ shortestDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"],
+ firstLetterDayNames: ["d", "s", "t", "q", "q", "s", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"],
+ abbreviatedMonthNames: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd-MM-yyyy",
+ longDate: "dddd, d' de 'MMMM' de 'yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "dddd, d' de 'MMMM' de 'yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d/M",
+ yearMonth: "MMMM' de 'yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(eiro)?/i,
+ feb: /^fev(ereiro)?/i,
+ mar: /^mar(ço)?/i,
+ apr: /^abr(il)?/i,
+ may: /^mai(o)?/i,
+ jun: /^jun(ho)?/i,
+ jul: /^jul(ho)?/i,
+ aug: /^ago(sto)?/i,
+ sep: /^set(embro)?/i,
+ oct: /^out(ubro)?/i,
+ nov: /^nov(embro)?/i,
+ dec: /^dez(embro)?/i,
+
+ sun: /^domingo/i,
+ mon: /^segunda-feira/i,
+ tue: /^terça-feira/i,
+ wed: /^quarta-feira/i,
+ thu: /^quinta-feira/i,
+ fri: /^sexta-feira/i,
+ sat: /^sábado/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ro-RO",
+ englishName: "Romanian (Romania)",
+ nativeName: "română (România)",
+
+ /* Day Name Strings */
+ dayNames: ["duminică", "luni", "marţi", "miercuri", "joi", "vineri", "sâmbătă"],
+ abbreviatedDayNames: ["D", "L", "Ma", "Mi", "J", "V", "S"],
+ shortestDayNames: ["D", "L", "Ma", "Mi", "J", "V", "S"],
+ firstLetterDayNames: ["D", "L", "M", "M", "J", "V", "S"],
+
+ /* Month Name Strings */
+ monthNames: ["ianuarie", "februarie", "martie", "aprilie", "mai", "iunie", "iulie", "august", "septembrie", "octombrie", "noiembrie", "decembrie"],
+ abbreviatedMonthNames: ["ian.", "feb.", "mar.", "apr.", "mai.", "iun.", "iul.", "aug.", "sep.", "oct.", "nov.", "dec."],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "d MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^ian(.(uarie)?)?/i,
+ feb: /^feb(.(ruarie)?)?/i,
+ mar: /^mar(.(tie)?)?/i,
+ apr: /^apr(.(ilie)?)?/i,
+ may: /^mai(.()?)?/i,
+ jun: /^iun(.(ie)?)?/i,
+ jul: /^iul(.(ie)?)?/i,
+ aug: /^aug(.(ust)?)?/i,
+ sep: /^sep(.(tembrie)?)?/i,
+ oct: /^oct(.(ombrie)?)?/i,
+ nov: /^noiembrie/i,
+ dec: /^dec(.(embrie)?)?/i,
+
+ sun: /^duminică/i,
+ mon: /^luni/i,
+ tue: /^marţi/i,
+ wed: /^miercuri/i,
+ thu: /^joi/i,
+ fri: /^vineri/i,
+ sat: /^sâmbătă/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "ru-RU",
+ englishName: "Russian (Russia)",
+ nativeName: "русский (Россия)",
+
+ /* Day Name Strings */
+ dayNames: ["воскресенье", "понедельник", "вторник", "среда", "четверг", "пятница", "суббота"],
+ abbreviatedDayNames: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
+ shortestDayNames: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
+ firstLetterDayNames: ["В", "П", "В", "С", "Ч", "П", "С"],
+
+ /* Month Name Strings */
+ monthNames: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"],
+ abbreviatedMonthNames: ["янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d MMMM yyyy 'г.'",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d MMMM yyyy 'г.' H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "MMMM dd",
+ yearMonth: "MMMM yyyy 'г.'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^янв(арь)?/i,
+ feb: /^фев(раль)?/i,
+ mar: /^мар(т)?/i,
+ apr: /^апр(ель)?/i,
+ may: /^май/i,
+ jun: /^июн(ь)?/i,
+ jul: /^июл(ь)?/i,
+ aug: /^авг(уст)?/i,
+ sep: /^сен(тябрь)?/i,
+ oct: /^окт(ябрь)?/i,
+ nov: /^ноя(брь)?/i,
+ dec: /^дек(абрь)?/i,
+
+ sun: /^воскресенье/i,
+ mon: /^понедельник/i,
+ tue: /^вторник/i,
+ wed: /^среда/i,
+ thu: /^четверг/i,
+ fri: /^пятница/i,
+ sat: /^суббота/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sk-SK",
+ englishName: "Slovak (Slovakia)",
+ nativeName: "slovenčina (Slovenská republika)",
+
+ /* Day Name Strings */
+ dayNames: ["nedeľa", "pondelok", "utorok", "streda", "štvrtok", "piatok", "sobota"],
+ abbreviatedDayNames: ["ne", "po", "ut", "st", "št", "pi", "so"],
+ shortestDayNames: ["ne", "po", "ut", "st", "št", "pi", "so"],
+ firstLetterDayNames: ["n", "p", "u", "s", "š", "p", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["január", "február", "marec", "apríl", "máj", "jún", "júl", "august", "september", "október", "november", "december"],
+ abbreviatedMonthNames: ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d. M. yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^január/i,
+ feb: /^február/i,
+ mar: /^marec/i,
+ apr: /^apríl/i,
+ may: /^máj/i,
+ jun: /^jún/i,
+ jul: /^júl/i,
+ aug: /^august/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^október/i,
+ nov: /^november/i,
+ dec: /^december/i,
+
+ sun: /^nedeľa/i,
+ mon: /^pondelok/i,
+ tue: /^utorok/i,
+ wed: /^streda/i,
+ thu: /^štvrtok/i,
+ fri: /^piatok/i,
+ sat: /^sobota/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sl-SI",
+ englishName: "Slovenian (Slovenia)",
+ nativeName: "slovenski (Slovenija)",
+
+ /* Day Name Strings */
+ dayNames: ["nedelja", "ponedeljek", "torek", "sreda", "četrtek", "petek", "sobota"],
+ abbreviatedDayNames: ["ned", "pon", "tor", "sre", "čet", "pet", "sob"],
+ shortestDayNames: ["ne", "po", "to", "sr", "če", "pe", "so"],
+ firstLetterDayNames: ["n", "p", "t", "s", "č", "p", "s"],
+
+ /* Month Name Strings */
+ monthNames: ["januar", "februar", "marec", "april", "maj", "junij", "julij", "avgust", "september", "oktober", "november", "december"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "avg", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "d.M.yyyy",
+ longDate: "d. MMMM yyyy",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d. MMMM yyyy H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d. MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uar)?/i,
+ feb: /^feb(ruar)?/i,
+ mar: /^mar(ec)?/i,
+ apr: /^apr(il)?/i,
+ may: /^maj/i,
+ jun: /^jun(ij)?/i,
+ jul: /^jul(ij)?/i,
+ aug: /^avg(ust)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^ne(d(elja)?)?/i,
+ mon: /^po(n(edeljek)?)?/i,
+ tue: /^to(r(ek)?)?/i,
+ wed: /^sr(e(da)?)?/i,
+ thu: /^če(t(rtek)?)?/i,
+ fri: /^pe(t(ek)?)?/i,
+ sat: /^so(b(ota)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "ar-SY",
- englishName: "Arabic (Syria)",
- nativeName: "العربية (سوريا)",
-
- /* Day Name Strings */
- dayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
- abbreviatedDayNames: ["الاحد", "الاثنين", "الثلاثاء", "الاربعاء", "الخميس", "الجمعة", "السبت"],
- shortestDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
- firstLetterDayNames: ["أ", "ا", "ث", "أ", "خ", "ج", "س"],
-
- /* Month Name Strings */
- monthNames: ["كانون الثاني", "شباط", "آذار", "نيسان", "أيار", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول"],
- abbreviatedMonthNames: ["كانون الثاني", "شباط", "آذار", "نيسان", "أيار", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول"],
-
- /* AM/PM Designators */
- amDesignator: "ص",
- pmDesignator: "م",
-
- firstDayOfWeek: 6,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd/MM/yyyy",
- longDate: "dd MMMM, yyyy",
- shortTime: "hh:mm tt",
- longTime: "hh:mm:ss tt",
- fullDateTime: "dd MMMM, yyyy hh:mm:ss tt",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM, yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^كانون الثاني/i,
- feb: /^شباط/i,
- mar: /^آذار/i,
- apr: /^نيسان/i,
- may: /^أيار/i,
- jun: /^حزيران/i,
- jul: /^تموز/i,
- aug: /^آب/i,
- sep: /^أيلول/i,
- oct: /^تشرين الأول/i,
- nov: /^تشرين الثاني/i,
- dec: /^كانون الأول/i,
-
- sun: /^الاحد/i,
- mon: /^ا(1)?/i,
- tue: /^الثلاثاء/i,
- wed: /^الاربعاء/i,
- thu: /^الخميس/i,
- fri: /^الجمعة/i,
- sat: /^السبت/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "bg-BG",
- englishName: "Bulgarian (Bulgaria)",
- nativeName: "български (България)",
-
- /* Day Name Strings */
- dayNames: ["неделя", "понеделник", "вторник", "сряда", "четвъртък", "петък", "събота"],
- abbreviatedDayNames: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
- shortestDayNames: ["не", "по", "вт", "ср", "че", "пе", "съ"],
- firstLetterDayNames: ["н", "п", "в", "с", "ч", "п", "с"],
-
- /* Month Name Strings */
- monthNames: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"],
- abbreviatedMonthNames: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd.M.yyyy 'г.'",
- longDate: "dd MMMM yyyy 'г.'",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "dd MMMM yyyy 'г.' HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM yyyy 'г.'"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^януари/i,
- feb: /^февруари/i,
- mar: /^март/i,
- apr: /^април/i,
- may: /^май/i,
- jun: /^юни/i,
- jul: /^юли/i,
- aug: /^август/i,
- sep: /^септември/i,
- oct: /^октомври/i,
- nov: /^ноември/i,
- dec: /^декември/i,
-
- sun: /^не((деля)?)?/i,
- mon: /^по((неделник)?)?/i,
- tue: /^вторник/i,
- wed: /^сряда/i,
- thu: /^че((твъртък)?)?/i,
- fri: /^пе((тък)?)?/i,
- sat: /^съ((бота)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "bs-Latn-BA",
- englishName: "Bosnian (Bosnia and Herzegovina)",
- nativeName: "bosanski (Bosna i Hercegovina)",
-
- /* Day Name Strings */
- dayNames: ["nedjelja", "ponedjeljak", "utorak", "srijeda", "četvrtak", "petak", "subota"],
- abbreviatedDayNames: ["ned", "pon", "uto", "sri", "čet", "pet", "sub"],
- shortestDayNames: ["ned", "pon", "uto", "sri", "čet", "pet", "sub"],
- firstLetterDayNames: ["n", "p", "u", "s", "č", "p", "s"],
-
- /* Month Name Strings */
- monthNames: ["januar", "februar", "mart", "april", "maj", "jun", "jul", "avgust", "septembar", "oktobar", "novembar", "decembar"],
- abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "avg", "sep", "okt", "nov", "dec"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "d.M.yyyy",
- longDate: "d. MMMM yyyy",
- shortTime: "H:mm:ss",
- longTime: "H:mm:ss",
- fullDateTime: "d. MMMM yyyy H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "MMMM dd",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(uar)?/i,
- feb: /^feb(ruar)?/i,
- mar: /^mar(t)?/i,
- apr: /^apr(il)?/i,
- may: /^maj/i,
- jun: /^jun/i,
- jul: /^jul/i,
- aug: /^avg(ust)?/i,
- sep: /^sep(tembar)?/i,
- oct: /^okt(obar)?/i,
- nov: /^nov(embar)?/i,
- dec: /^dec(embar)?/i,
-
- sun: /^nedjelja/i,
- mon: /^ponedjeljak/i,
- tue: /^utorak/i,
- wed: /^srijeda/i,
- thu: /^četvrtak/i,
- fri: /^petak/i,
- sat: /^subota/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "ca-ES",
- englishName: "Catalan (Catalan)",
- nativeName: "català (català)",
-
- /* Day Name Strings */
- dayNames: ["diumenge", "dilluns", "dimarts", "dimecres", "dijous", "divendres", "dissabte"],
- abbreviatedDayNames: ["dg.", "dl.", "dt.", "dc.", "dj.", "dv.", "ds."],
- shortestDayNames: ["dg", "dl", "dt", "dc", "dj", "dv", "ds"],
- firstLetterDayNames: ["d", "d", "d", "d", "d", "d", "d"],
-
- /* Month Name Strings */
- monthNames: ["gener", "febrer", "març", "abril", "maig", "juny", "juliol", "agost", "setembre", "octubre", "novembre", "desembre"],
- abbreviatedMonthNames: ["gen", "feb", "març", "abr", "maig", "juny", "jul", "ag", "set", "oct", "nov", "des"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd/MM/yyyy",
- longDate: "dddd, d' / 'MMMM' / 'yyyy",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "dddd, d' / 'MMMM' / 'yyyy HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM' / 'yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^gen(er)?/i,
- feb: /^feb(rer)?/i,
- mar: /^març/i,
- apr: /^abr(il)?/i,
- may: /^maig/i,
- jun: /^juny/i,
- jul: /^jul(iol)?/i,
- aug: /^ag(ost)?/i,
- sep: /^set(embre)?/i,
- oct: /^oct(ubre)?/i,
- nov: /^nov(embre)?/i,
- dec: /^des(embre)?/i,
-
- sun: /^dg((.(umenge)?)?)?/i,
- mon: /^dl((.(lluns)?)?)?/i,
- tue: /^dt((.(marts)?)?)?/i,
- wed: /^dc((.(mecres)?)?)?/i,
- thu: /^dj((.(jous)?)?)?/i,
- fri: /^dv((.(vendres)?)?)?/i,
- sat: /^ds((.(ssabte)?)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-function sbarToggle()
-{
- var body = $(document.body), pref_value;
-
- if (body.hasClassName('rightPanel')) {
- pref_value = 0;
- body.removeClassName('rightPanel');
- } else {
- pref_value = 1;
- body.addClassName('rightPanel');
- }
-
- new Ajax.Request(KronolithVar.pref_api_url, { parameters: { app: 'kronolith', pref: 'show_panel', value: pref_value } });
-}
-
-function removeTag(tagid)
-{
-
-}
-document.observe('dom:loaded', function() {
- $$('#pageControlsInner .checkbox').invoke('observe', 'click', function() {
- Views.invalidate();
- ShowView(kronolithView, { date: kronolithDate.getFullYear() + (kronolithDate.getMonth() + 1).toPaddedString(2) + kronolithDate.getDate().toPaddedString(2), toggle_calendar: this.value }, false);
- });
-
- $$('#pageControlsInner .calendar-info').invoke('observe', 'click', function() {
- RedBox.loading();
- var calendar_id = this.up().select('.checkbox').first().value;
- new Ajax.Request(KronolithVar.calendar_info_url, {
- parameters: { c: calendar_id },
- method: 'get',
- onSuccess: function(transport) {
- RedBox.showHtml('<div id="RB_info">' + transport.responseText + '<input type="button" class="button" onclick="RedBox.close();" value="' + KronolithText.close + '" /></div>');
- },
- onFailure: function(transport) {
- RedBox.close();
- }
- });
- });
-});
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "cs-CZ",
- englishName: "Czech (Czech Republic)",
- nativeName: "čeština (Česká republika)",
-
- /* Day Name Strings */
- dayNames: ["neděle", "pondělí", "úterý", "středa", "čtvrtek", "pátek", "sobota"],
- abbreviatedDayNames: ["ne", "po", "út", "st", "čt", "pá", "so"],
- shortestDayNames: ["ne", "po", "út", "st", "čt", "pá", "so"],
- firstLetterDayNames: ["n", "p", "ú", "s", "č", "p", "s"],
-
- /* Month Name Strings */
- monthNames: ["leden", "únor", "březen", "duben", "květen", "červen", "červenec", "srpen", "září", "říjen", "listopad", "prosinec"],
- abbreviatedMonthNames: ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"],
-
- /* AM/PM Designators */
- amDesignator: "dop.",
- pmDesignator: "odp.",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "d.M.yyyy",
- longDate: "d. MMMM yyyy",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "d. MMMM yyyy H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^leden/i,
- feb: /^únor/i,
- mar: /^březen/i,
- apr: /^duben/i,
- may: /^květen/i,
- jun: /^červen/i,
- jul: /^červenec/i,
- aug: /^srpen/i,
- sep: /^září/i,
- oct: /^říjen/i,
- nov: /^listopad/i,
- dec: /^prosinec/i,
-
- sun: /^neděle/i,
- mon: /^pondělí/i,
- tue: /^úterý/i,
- wed: /^středa/i,
- thu: /^čtvrtek/i,
- fri: /^pátek/i,
- sat: /^sobota/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "da-DK",
- englishName: "Danish (Denmark)",
- nativeName: "dansk (Danmark)",
-
- /* Day Name Strings */
- dayNames: ["søndag", "mandag", "tirsdag", "onsdag", "torsdag", "fredag", "lørdag"],
- abbreviatedDayNames: ["sø", "ma", "ti", "on", "to", "fr", "lø"],
- shortestDayNames: ["sø", "ma", "ti", "on", "to", "fr", "lø"],
- firstLetterDayNames: ["s", "m", "t", "o", "t", "f", "l"],
-
- /* Month Name Strings */
- monthNames: ["januar", "februar", "marts", "april", "maj", "juni", "juli", "august", "september", "oktober", "november", "december"],
- abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd-MM-yyyy",
- longDate: "d. MMMM yyyy",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "d. MMMM yyyy HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "d. MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(uar)?/i,
- feb: /^feb(ruar)?/i,
- mar: /^mar(ts)?/i,
- apr: /^apr(il)?/i,
- may: /^maj/i,
- jun: /^jun(i)?/i,
- jul: /^jul(i)?/i,
- aug: /^aug(ust)?/i,
- sep: /^sep(t(ember)?)?/i,
- oct: /^okt(ober)?/i,
- nov: /^nov(ember)?/i,
- dec: /^dec(ember)?/i,
-
- sun: /^søndag/i,
- mon: /^mandag/i,
- tue: /^tirsdag/i,
- wed: /^onsdag/i,
- thu: /^torsdag/i,
- fri: /^fredag/i,
- sat: /^lørdag/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-/**
- * @version: 1.0 Alpha-1
- * @author: Coolite Inc. http://www.coolite.com/
- * @date: 2008-04-13
- * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
- * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
- * @website: http://www.datejs.com/
- */
-
-(function () {
- var $D = Date,
- $P = $D.prototype,
- $C = $D.CultureInfo,
- p = function (s, l) {
- if (!l) {
- l = 2;
- }
- return ("000" + s).slice(l * -1);
- };
-
- /**
- * Resets the time of this Date object to 12:00 AM (00:00), which is the start of the day.
- * @param {Boolean} .clone() this date instance before clearing Time
- * @return {Date} this
- */
- $P.clearTime = function () {
- this.setHours(0);
- this.setMinutes(0);
- this.setSeconds(0);
- this.setMilliseconds(0);
- return this;
- };
-
- /**
- * Resets the time of this Date object to the current time ('now').
- * @return {Date} this
- */
- $P.setTimeToNow = function () {
- var n = new Date();
- this.setHours(n.getHours());
- this.setMinutes(n.getMinutes());
- this.setSeconds(n.getSeconds());
- this.setMilliseconds(n.getMilliseconds());
- return this;
- };
-
- /**
- * Gets a date that is set to the current date. The time is set to the start of the day (00:00 or 12:00 AM).
- * @return {Date} The current date.
- */
- $D.today = function () {
- return new Date().clearTime();
- };
-
- /**
- * Compares the first date to the second date and returns an number indication of their relative values.
- * @param {Date} First Date object to compare [Required].
- * @param {Date} Second Date object to compare to [Required].
- * @return {Number} -1 = date1 is lessthan date2. 0 = values are equal. 1 = date1 is greaterthan date2.
- */
- $D.compare = function (date1, date2) {
- if (isNaN(date1) || isNaN(date2)) {
- throw new Error(date1 + " - " + date2);
- } else if (date1 instanceof Date && date2 instanceof Date) {
- return (date1 < date2) ? -1 : (date1 > date2) ? 1 : 0;
- } else {
- throw new TypeError(date1 + " - " + date2);
- }
- };
-
- /**
- * Compares the first Date object to the second Date object and returns true if they are equal.
- * @param {Date} First Date object to compare [Required]
- * @param {Date} Second Date object to compare to [Required]
- * @return {Boolean} true if dates are equal. false if they are not equal.
- */
- $D.equals = function (date1, date2) {
- return (date1.compareTo(date2) === 0);
- };
-
- /**
- * Gets the day number (0-6) if given a CultureInfo specific string which is a valid dayName, abbreviatedDayName or shortestDayName (two char).
- * @param {String} The name of the day (eg. "Monday, "Mon", "tuesday", "tue", "We", "we").
- * @return {Number} The day number
- */
- $D.getDayNumberFromName = function (name) {
- var n = $C.dayNames, m = $C.abbreviatedDayNames, o = $C.shortestDayNames, s = name.toLowerCase();
- for (var i = 0; i < n.length; i++) {
- if (n[i].toLowerCase() == s || m[i].toLowerCase() == s || o[i].toLowerCase() == s) {
- return i;
- }
- }
- return -1;
- };
-
- /**
- * Gets the month number (0-11) if given a Culture Info specific string which is a valid monthName or abbreviatedMonthName.
- * @param {String} The name of the month (eg. "February, "Feb", "october", "oct").
- * @return {Number} The day number
- */
- $D.getMonthNumberFromName = function (name) {
- var n = $C.monthNames, m = $C.abbreviatedMonthNames, s = name.toLowerCase();
- for (var i = 0; i < n.length; i++) {
- if (n[i].toLowerCase() == s || m[i].toLowerCase() == s) {
- return i;
- }
- }
- return -1;
- };
-
- /**
- * Determines if the current date instance is within a LeapYear.
- * @param {Number} The year.
- * @return {Boolean} true if date is within a LeapYear, otherwise false.
- */
- $D.isLeapYear = function (year) {
- return ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);
- };
-
- /**
- * Gets the number of days in the month, given a year and month value. Automatically corrects for LeapYear.
- * @param {Number} The year.
- * @param {Number} The month (0-11).
- * @return {Number} The number of days in the month.
- */
- $D.getDaysInMonth = function (year, month) {
- return [31, ($D.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
- };
-
- $D.getTimezoneAbbreviation = function (offset) {
- var z = $C.timezones, p;
- for (var i = 0; i < z.length; i++) {
- if (z[i].offset === offset) {
- return z[i].name;
- }
- }
- return null;
- };
-
- $D.getTimezoneOffset = function (name) {
- var z = $C.timezones, p;
- for (var i = 0; i < z.length; i++) {
- if (z[i].name === name.toUpperCase()) {
- return z[i].offset;
- }
- }
- return null;
- };
-
- /**
- * Returns a new Date object that is an exact date and time copy of the original instance.
- * @return {Date} A new Date instance
- */
- $P.clone = function () {
- return new Date(this.getTime());
- };
-
- /**
- * Compares this instance to a Date object and returns an number indication of their relative values.
- * @param {Date} Date object to compare [Required]
- * @return {Number} -1 = this is lessthan date. 0 = values are equal. 1 = this is greaterthan date.
- */
- $P.compareTo = function (date) {
- return Date.compare(this, date);
- };
-
- /**
- * Compares this instance to another Date object and returns true if they are equal.
- * @param {Date} Date object to compare. If no date to compare, new Date() [now] is used.
- * @return {Boolean} true if dates are equal. false if they are not equal.
- */
- $P.equals = function (date) {
- return Date.equals(this, date || new Date());
- };
-
- /**
- * Determines if this instance is between a range of two dates or equal to either the start or end dates.
- * @param {Date} Start of range [Required]
- * @param {Date} End of range [Required]
- * @return {Boolean} true is this is between or equal to the start and end dates, else false
- */
- $P.between = function (start, end) {
- return this.getTime() >= start.getTime() && this.getTime() <= end.getTime();
- };
-
- /**
- * Determines if this date occurs after the date to compare to.
- * @param {Date} Date object to compare. If no date to compare, new Date() ("now") is used.
- * @return {Boolean} true if this date instance is greater than the date to compare to (or "now"), otherwise false.
- */
- $P.isAfter = function (date) {
- return this.compareTo(date || new Date()) === 1;
- };
-
- /**
- * Determines if this date occurs before the date to compare to.
- * @param {Date} Date object to compare. If no date to compare, new Date() ("now") is used.
- * @return {Boolean} true if this date instance is less than the date to compare to (or "now").
- */
- $P.isBefore = function (date) {
- return (this.compareTo(date || new Date()) === -1);
- };
-
- /**
- * Determines if the current Date instance occurs today.
- * @return {Boolean} true if this date instance is 'today', otherwise false.
- */
-
- /**
- * Determines if the current Date instance occurs on the same Date as the supplied 'date'.
- * If no 'date' to compare to is provided, the current Date instance is compared to 'today'.
- * @param {date} Date object to compare. If no date to compare, the current Date ("now") is used.
- * @return {Boolean} true if this Date instance occurs on the same Day as the supplied 'date'.
- */
- $P.isToday = $P.isSameDay = function (date) {
- return this.clone().clearTime().equals((date || new Date()).clone().clearTime());
- };
-
- /**
- * Adds the specified number of milliseconds to this instance.
- * @param {Number} The number of milliseconds to add. The number can be positive or negative [Required]
- * @return {Date} this
- */
- $P.addMilliseconds = function (value) {
- this.setMilliseconds(this.getMilliseconds() + value * 1);
- return this;
- };
-
- /**
- * Adds the specified number of seconds to this instance.
- * @param {Number} The number of seconds to add. The number can be positive or negative [Required]
- * @return {Date} this
- */
- $P.addSeconds = function (value) {
- return this.addMilliseconds(value * 1000);
- };
-
- /**
- * Adds the specified number of seconds to this instance.
- * @param {Number} The number of seconds to add. The number can be positive or negative [Required]
- * @return {Date} this
- */
- $P.addMinutes = function (value) {
- return this.addMilliseconds(value * 60000); /* 60*1000 */
- };
-
- /**
- * Adds the specified number of hours to this instance.
- * @param {Number} The number of hours to add. The number can be positive or negative [Required]
- * @return {Date} this
- */
- $P.addHours = function (value) {
- return this.addMilliseconds(value * 3600000); /* 60*60*1000 */
- };
-
- /**
- * Adds the specified number of days to this instance.
- * @param {Number} The number of days to add. The number can be positive or negative [Required]
- * @return {Date} this
- */
- $P.addDays = function (value) {
- this.setDate(this.getDate() + value * 1);
- return this;
- };
-
- /**
- * Adds the specified number of weeks to this instance.
- * @param {Number} The number of weeks to add. The number can be positive or negative [Required]
- * @return {Date} this
- */
- $P.addWeeks = function (value) {
- return this.addDays(value * 7);
- };
-
- /**
- * Adds the specified number of months to this instance.
- * @param {Number} The number of months to add. The number can be positive or negative [Required]
- * @return {Date} this
- */
- $P.addMonths = function (value) {
- var n = this.getDate();
- this.setDate(1);
- this.setMonth(this.getMonth() + value * 1);
- this.setDate(Math.min(n, $D.getDaysInMonth(this.getFullYear(), this.getMonth())));
- return this;
- };
-
- /**
- * Adds the specified number of years to this instance.
- * @param {Number} The number of years to add. The number can be positive or negative [Required]
- * @return {Date} this
- */
- $P.addYears = function (value) {
- return this.addMonths(value * 12);
- };
-
- /**
- * Adds (or subtracts) to the value of the years, months, weeks, days, hours, minutes, seconds, milliseconds of the date instance using given configuration object. Positive and Negative values allowed.
- * Example
- <pre><code>
- Date.today().add( { days: 1, months: 1 } )
-
- new Date().add( { years: -1 } )
- </code></pre>
- * @param {Object} Configuration object containing attributes (months, days, etc.)
- * @return {Date} this
- */
- $P.add = function (config) {
- if (typeof config == "number") {
- this._orient = config;
- return this;
- }
-
- var x = config;
-
- if (x.milliseconds) {
- this.addMilliseconds(x.milliseconds);
- }
- if (x.seconds) {
- this.addSeconds(x.seconds);
- }
- if (x.minutes) {
- this.addMinutes(x.minutes);
- }
- if (x.hours) {
- this.addHours(x.hours);
- }
- if (x.weeks) {
- this.addWeeks(x.weeks);
- }
- if (x.months) {
- this.addMonths(x.months);
- }
- if (x.years) {
- this.addYears(x.years);
- }
- if (x.days) {
- this.addDays(x.days);
- }
- return this;
- };
-
- var $y, $m, $d;
-
- /**
- * Get the week number. Week one (1) is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
- * This algorithm is a JavaScript port of the work presented by Claus Tøndering at http://www.tondering.dk/claus/cal/node8.html#SECTION00880000000000000000
- * .getWeek() Algorithm Copyright (c) 2008 Claus Tondering.
- * The .getWeek() function does NOT convert the date to UTC. The local datetime is used. Please use .getISOWeek() to get the week of the UTC converted date.
- * @return {Number} 1 to 53
- */
- $P.getWeek = function () {
- var a, b, c, d, e, f, g, n, s, w;
-
- $y = (!$y) ? this.getFullYear() : $y;
- $m = (!$m) ? this.getMonth() + 1 : $m;
- $d = (!$d) ? this.getDate() : $d;
-
- if ($m <= 2) {
- a = $y - 1;
- b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0);
- c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0);
- s = b - c;
- e = 0;
- f = $d - 1 + (31 * ($m - 1));
- } else {
- a = $y;
- b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0);
- c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0);
- s = b - c;
- e = s + 1;
- f = $d + ((153 * ($m - 3) + 2) / 5 | 0) + 58 + s;
- }
-
- g = (a + b) % 7;
- d = (f + g - e) % 7;
- n = f + 3 - d;
-
- if (n < 0) {
- w = 53 - ((g - s) / 5 | 0);
- } else if (n > 364 + s) {
- w = 1;
- } else {
- w = (n / 7 | 0) + 1;
- }
-
- $y = $m = $d = null;
-
- return w;
- };
-
- /**
- * Get the ISO 8601 week number. Week one ("01") is the week which contains the first Thursday of the year. Monday is considered the first day of the week.
- * The .getISOWeek() function does convert the date to it's UTC value. Please use .getWeek() to get the week of the local date.
- * @return {String} "01" to "53"
- */
- $P.getISOWeek = function () {
- $y = this.getUTCFullYear();
- $m = this.getUTCMonth() + 1;
- $d = this.getUTCDate();
- return p(this.getWeek());
- };
-
- /**
- * Moves the date to Monday of the week set. Week one (1) is the week which contains the first Thursday of the year.
- * @param {Number} A Number (1 to 53) that represents the week of the year.
- * @return {Date} this
- */
- $P.setWeek = function (n) {
- return this.moveToDayOfWeek(1).addWeeks(n - this.getWeek());
- };
-
- // private
- var validate = function (n, min, max, name) {
- if (typeof n == "undefined") {
- return false;
- } else if (typeof n != "number") {
- throw new TypeError(n + " is not a Number.");
- } else if (n < min || n > max) {
- throw new RangeError(n + " is not a valid value for " + name + ".");
- }
- return true;
- };
-
- /**
- * Validates the number is within an acceptable range for milliseconds [0-999].
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateMillisecond = function (value) {
- return validate(value, 0, 999, "millisecond");
- };
-
- /**
- * Validates the number is within an acceptable range for seconds [0-59].
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateSecond = function (value) {
- return validate(value, 0, 59, "second");
- };
-
- /**
- * Validates the number is within an acceptable range for minutes [0-59].
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateMinute = function (value) {
- return validate(value, 0, 59, "minute");
- };
-
- /**
- * Validates the number is within an acceptable range for hours [0-23].
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateHour = function (value) {
- return validate(value, 0, 23, "hour");
- };
-
- /**
- * Validates the number is within an acceptable range for the days in a month [0-MaxDaysInMonth].
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateDay = function (value, year, month) {
- return validate(value, 1, $D.getDaysInMonth(year, month), "day");
- };
-
- /**
- * Validates the number is within an acceptable range for months [0-11].
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateMonth = function (value) {
- return validate(value, 0, 11, "month");
- };
-
- /**
- * Validates the number is within an acceptable range for years.
- * @param {Number} The number to check if within range.
- * @return {Boolean} true if within range, otherwise false.
- */
- $D.validateYear = function (value) {
- return validate(value, 0, 9999, "year");
- };
-
- /**
- * Set the value of year, month, day, hour, minute, second, millisecond of date instance using given configuration object.
- * Example
- <pre><code>
- Date.today().set( { day: 20, month: 1 } )
-
- new Date().set( { millisecond: 0 } )
- </code></pre>
- *
- * @param {Object} Configuration object containing attributes (month, day, etc.)
- * @return {Date} this
- */
- $P.set = function (config) {
- if ($D.validateMillisecond(config.millisecond)) {
- this.addMilliseconds(config.millisecond - this.getMilliseconds());
- }
-
- if ($D.validateSecond(config.second)) {
- this.addSeconds(config.second - this.getSeconds());
- }
-
- if ($D.validateMinute(config.minute)) {
- this.addMinutes(config.minute - this.getMinutes());
- }
-
- if ($D.validateHour(config.hour)) {
- this.addHours(config.hour - this.getHours());
- }
-
- if ($D.validateMonth(config.month)) {
- this.addMonths(config.month - this.getMonth());
- }
-
- if ($D.validateYear(config.year)) {
- this.addYears(config.year - this.getFullYear());
- }
-
- /* day has to go last because you can't validate the day without first knowing the month */
- if ($D.validateDay(config.day, this.getFullYear(), this.getMonth())) {
- this.addDays(config.day - this.getDate());
- }
-
- if (config.timezone) {
- this.setTimezone(config.timezone);
- }
-
- if (config.timezoneOffset) {
- this.setTimezoneOffset(config.timezoneOffset);
- }
-
- if (config.week && validate(config.week, 0, 53, "week")) {
- this.setWeek(config.week);
- }
-
- return this;
- };
-
- /**
- * Moves the date to the first day of the month.
- * @return {Date} this
- */
- $P.moveToFirstDayOfMonth = function () {
- return this.set({ day: 1 });
- };
-
- /**
- * Moves the date to the last day of the month.
- * @return {Date} this
- */
- $P.moveToLastDayOfMonth = function () {
- return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())});
- };
-
- /**
- * Moves the date to the next n'th occurrence of the dayOfWeek starting from the beginning of the month. The number (-1) is a magic number and will return the last occurrence of the dayOfWeek in the month.
- * @param {Number} The dayOfWeek to move to
- * @param {Number} The n'th occurrence to move to. Use (-1) to return the last occurrence in the month
- * @return {Date} this
- */
- $P.moveToNthOccurrence = function (dayOfWeek, occurrence) {
- var shift = 0;
- if (occurrence > 0) {
- shift = occurrence - 1;
- }
- else if (occurrence === -1) {
- this.moveToLastDayOfMonth();
- if (this.getDay() !== dayOfWeek) {
- this.moveToDayOfWeek(dayOfWeek, -1);
- }
- return this;
- }
- return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift);
- };
-
- /**
- * Move to the next or last dayOfWeek based on the orient value.
- * @param {Number} The dayOfWeek to move to
- * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
- * @return {Date} this
- */
- $P.moveToDayOfWeek = function (dayOfWeek, orient) {
- var diff = (dayOfWeek - this.getDay() + 7 * (orient || +1)) % 7;
- return this.addDays((diff === 0) ? diff += 7 * (orient || +1) : diff);
- };
-
- /**
- * Move to the next or last month based on the orient value.
- * @param {Number} The month to move to. 0 = January, 11 = December
- * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional]
- * @return {Date} this
- */
- $P.moveToMonth = function (month, orient) {
- var diff = (month - this.getMonth() + 12 * (orient || +1)) % 12;
- return this.addMonths((diff === 0) ? diff += 12 * (orient || +1) : diff);
- };
-
- /**
- * Get the Ordinal day (numeric day number) of the year, adjusted for leap year.
- * @return {Number} 1 through 365 (366 in leap years)
- */
- $P.getOrdinalNumber = function () {
- return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
- };
-
- /**
- * Get the time zone abbreviation of the current date.
- * @return {String} The abbreviated time zone name (e.g. "EST")
- */
- $P.getTimezone = function () {
- return $D.getTimezoneAbbreviation(this.getUTCOffset());
- };
-
- $P.setTimezoneOffset = function (offset) {
- var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10;
- return this.addMinutes(there - here);
- };
-
- $P.setTimezone = function (offset) {
- return this.setTimezoneOffset($D.getTimezoneOffset(offset));
- };
-
- /**
- * Indicates whether Daylight Saving Time is observed in the current time zone.
- * @return {Boolean} true|false
- */
- $P.hasDaylightSavingTime = function () {
- return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() !== Date.today().set({month: 6, day: 1}).getTimezoneOffset());
- };
-
- /**
- * Indicates whether this Date instance is within the Daylight Saving Time range for the current time zone.
- * @return {Boolean} true|false
- */
- $P.isDaylightSavingTime = function () {
- return Date.today().set({month: 0, day: 1}).getTimezoneOffset() != this.getTimezoneOffset();
- };
-
- /**
- * Get the offset from UTC of the current date.
- * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500")
- */
- $P.getUTCOffset = function () {
- var n = this.getTimezoneOffset() * -10 / 6, r;
- if (n < 0) {
- r = (n - 10000).toString();
- return r.charAt(0) + r.substr(2);
- } else {
- r = (n + 10000).toString();
- return "+" + r.substr(1);
- }
- };
-
- /**
- * Returns the number of milliseconds between this date and date.
- * @param {Date} Defaults to now
- * @return {Number} The diff in milliseconds
- */
- $P.getElapsed = function (date) {
- return (date || new Date()) - this;
- };
-
- if (!$P.toISOString) {
- /**
- * Converts the current date instance into a string with an ISO 8601 format. The date is converted to it's UTC value.
- * @return {String} ISO 8601 string of date
- */
- $P.toISOString = function () {
- // From http://www.json.org/json.js. Public Domain.
- function f(n) {
- return n < 10 ? '0' + n : n;
- }
-
- return '"' + this.getUTCFullYear() + '-' +
- f(this.getUTCMonth() + 1) + '-' +
- f(this.getUTCDate()) + 'T' +
- f(this.getUTCHours()) + ':' +
- f(this.getUTCMinutes()) + ':' +
- f(this.getUTCSeconds()) + 'Z"';
- };
- }
-
- // private
- $P._toString = $P.toString;
-
- /**
- * Converts the value of the current Date object to its equivalent string representation.
- * Format Specifiers
- <pre>
- CUSTOM DATE AND TIME FORMAT STRINGS
- Format Description Example
- ------ --------------------------------------------------------------------------- -----------------------
- s The seconds of the minute between 0-59. "0" to "59"
- ss The seconds of the minute with leading zero if required. "00" to "59"
-
- m The minute of the hour between 0-59. "0" or "59"
- mm The minute of the hour with leading zero if required. "00" or "59"
-
- h The hour of the day between 1-12. "1" to "12"
- hh The hour of the day with leading zero if required. "01" to "12"
-
- H The hour of the day between 0-23. "0" to "23"
- HH The hour of the day with leading zero if required. "00" to "23"
-
- d The day of the month between 1 and 31. "1" to "31"
- dd The day of the month with leading zero if required. "01" to "31"
- ddd Abbreviated day name. $C.abbreviatedDayNames. "Mon" to "Sun"
- dddd The full day name. $C.dayNames. "Monday" to "Sunday"
-
- M The month of the year between 1-12. "1" to "12"
- MM The month of the year with leading zero if required. "01" to "12"
- MMM Abbreviated month name. $C.abbreviatedMonthNames. "Jan" to "Dec"
- MMMM The full month name. $C.monthNames. "January" to "December"
-
- yy The year as a two-digit number. "99" or "08"
- yyyy The full four digit year. "1999" or "2008"
-
- t Displays the first character of the A.M./P.M. designator. "A" or "P"
- $C.amDesignator or $C.pmDesignator
- tt Displays the A.M./P.M. designator. "AM" or "PM"
- $C.amDesignator or $C.pmDesignator
-
- S The ordinal suffix ("st, "nd", "rd" or "th") of the current day. "st, "nd", "rd" or "th"
-
-|| *Format* || *Description* || *Example* ||
-|| d || The CultureInfo shortDate Format Pattern || "M/d/yyyy" ||
-|| D || The CultureInfo longDate Format Pattern || "dddd, MMMM dd, yyyy" ||
-|| F || The CultureInfo fullDateTime Format Pattern || "dddd, MMMM dd, yyyy h:mm:ss tt" ||
-|| m || The CultureInfo monthDay Format Pattern || "MMMM dd" ||
-|| r || The CultureInfo rfc1123 Format Pattern || "ddd, dd MMM yyyy HH:mm:ss GMT" ||
-|| s || The CultureInfo sortableDateTime Format Pattern || "yyyy-MM-ddTHH:mm:ss" ||
-|| t || The CultureInfo shortTime Format Pattern || "h:mm tt" ||
-|| T || The CultureInfo longTime Format Pattern || "h:mm:ss tt" ||
-|| u || The CultureInfo universalSortableDateTime Format Pattern || "yyyy-MM-dd HH:mm:ssZ" ||
-|| y || The CultureInfo yearMonth Format Pattern || "MMMM, yyyy" ||
-
-
- STANDARD DATE AND TIME FORMAT STRINGS
- Format Description Example ("en-US")
- ------ --------------------------------------------------------------------------- -----------------------
- d The CultureInfo shortDate Format Pattern "M/d/yyyy"
- D The CultureInfo longDate Format Pattern "dddd, MMMM dd, yyyy"
- F The CultureInfo fullDateTime Format Pattern "dddd, MMMM dd, yyyy h:mm:ss tt"
- m The CultureInfo monthDay Format Pattern "MMMM dd"
- r The CultureInfo rfc1123 Format Pattern "ddd, dd MMM yyyy HH:mm:ss GMT"
- s The CultureInfo sortableDateTime Format Pattern "yyyy-MM-ddTHH:mm:ss"
- t The CultureInfo shortTime Format Pattern "h:mm tt"
- T The CultureInfo longTime Format Pattern "h:mm:ss tt"
- u The CultureInfo universalSortableDateTime Format Pattern "yyyy-MM-dd HH:mm:ssZ"
- y The CultureInfo yearMonth Format Pattern "MMMM, yyyy"
- </pre>
- * @param {String} A format string consisting of one or more format spcifiers [Optional].
- * @return {String} A string representation of the current Date object.
- */
- $P.toString = function (format) {
- var x = this;
-
- // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and
- // may vary by culture.
- if (format && format.length == 1) {
- var c = $C.formatPatterns;
- x.t = x.toString;
- switch (format) {
- case "d":
- return x.t(c.shortDate);
- case "D":
- return x.t(c.longDate);
- case "F":
- return x.t(c.fullDateTime);
- case "m":
- return x.t(c.monthDay);
- case "r":
- return x.t(c.rfc1123);
- case "s":
- return x.t(c.sortableDateTime);
- case "t":
- return x.t(c.shortTime);
- case "T":
- return x.t(c.longTime);
- case "u":
- return x.t(c.universalSortableDateTime);
- case "y":
- return x.t(c.yearMonth);
- }
- }
-
- var ord = function (n) {
- switch (n * 1) {
- case 1:
- case 21:
- case 31:
- return "st";
- case 2:
- case 22:
- return "nd";
- case 3:
- case 23:
- return "rd";
- default:
- return "th";
- }
- };
-
- return format ? format.replace(/(\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g,
- function (m) {
- if (m.charAt(0) === "\\") {
- return m.replace("\\", "");
- }
- x.h = x.getHours;
- switch (m) {
- case "hh":
- return p(x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12));
- case "h":
- return x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12);
- case "HH":
- return p(x.h());
- case "H":
- return x.h();
- case "mm":
- return p(x.getMinutes());
- case "m":
- return x.getMinutes();
- case "ss":
- return p(x.getSeconds());
- case "s":
- return x.getSeconds();
- case "yyyy":
- return p(x.getFullYear(), 4);
- case "yy":
- return p(x.getFullYear());
- case "dddd":
- return $C.dayNames[x.getDay()];
- case "ddd":
- return $C.abbreviatedDayNames[x.getDay()];
- case "dd":
- return p(x.getDate());
- case "d":
- return x.getDate();
- case "MMMM":
- return $C.monthNames[x.getMonth()];
- case "MMM":
- return $C.abbreviatedMonthNames[x.getMonth()];
- case "MM":
- return p((x.getMonth() + 1));
- case "M":
- return x.getMonth() + 1;
- case "t":
- return x.h() < 12 ? $C.amDesignator.substring(0, 1) : $C.pmDesignator.substring(0, 1);
- case "tt":
- return x.h() < 12 ? $C.amDesignator : $C.pmDesignator;
- case "S":
- return ord(x.getDate());
- default:
- return m;
- }
- }
- ) : this._toString();
- };
-}()); /**
- * @version: 1.0 Alpha-1
- * @author: Coolite Inc. http://www.coolite.com/
- * @date: 2008-04-13
- * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
- * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
- * @website: http://www.datejs.com/
- */
-
-/**
- **************************************************************
- ** SugarPak - Domain Specific Language - Syntactical Sugar **
- **************************************************************
- */
-
-(function () {
- var $D = Date, $P = $D.prototype, $C = $D.CultureInfo, $N = Number.prototype;
-
- // private
- $P._orient = +1;
-
- // private
- $P._nth = null;
-
- // private
- $P._is = false;
-
- // private
- $P._same = false;
-
- // private
- $P._isSecond = false;
-
- // private
- $N._dateElement = "day";
-
- /**
- * Moves the date to the next instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
- * Example
- <pre><code>
- Date.today().next().friday();
- Date.today().next().fri();
- Date.today().next().march();
- Date.today().next().mar();
- Date.today().next().week();
- </code></pre>
- *
- * @return {Date} date
- */
- $P.next = function () {
- this._orient = +1;
- return this;
- };
-
- /**
- * Creates a new Date (Date.today()) and moves the date to the next instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
- * Example
- <pre><code>
- Date.next().friday();
- Date.next().fri();
- Date.next().march();
- Date.next().mar();
- Date.next().week();
- </code></pre>
- *
- * @return {Date} date
- */
- $D.next = function () {
- return $D.today().next();
- };
-
- /**
- * Moves the date to the previous instance of a date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
- * Example
- <pre><code>
- Date.today().last().friday();
- Date.today().last().fri();
- Date.today().last().march();
- Date.today().last().mar();
- Date.today().last().week();
- </code></pre>
- *
- * @return {Date} date
- */
- $P.last = $P.prev = $P.previous = function () {
- this._orient = -1;
- return this;
- };
-
- /**
- * Creates a new Date (Date.today()) and moves the date to the previous instance of the date as specified by the subsequent date element function (eg. .day(), .month()), month name function (eg. .january(), .jan()) or day name function (eg. .friday(), fri()).
- * Example
- <pre><code>
- Date.last().friday();
- Date.last().fri();
- Date.previous().march();
- Date.prev().mar();
- Date.last().week();
- </code></pre>
- *
- * @return {Date} date
- */
- $D.last = $D.prev = $D.previous = function () {
- return $D.today().last();
- };
-
- /**
- * Performs a equality check when followed by either a month name, day name or .weekday() function.
- * Example
- <pre><code>
- Date.today().is().friday(); // true|false
- Date.today().is().fri();
- Date.today().is().march();
- Date.today().is().mar();
- </code></pre>
- *
- * @return {Boolean} true|false
- */
- $P.is = function () {
- this._is = true;
- return this;
- };
-
- /**
- * Determines if two date objects occur on/in exactly the same instance of the subsequent date part function.
- * The function .same() must be followed by a date part function (example: .day(), .month(), .year(), etc).
- *
- * An optional Date can be passed in the date part function. If now date is passed as a parameter, 'Now' is used.
- *
- * The following example demonstrates how to determine if two dates fall on the exact same day.
- *
- * Example
- <pre><code>
- var d1 = Date.today(); // today at 00:00
- var d2 = new Date(); // exactly now.
-
- // Do they occur on the same day?
- d1.same().day(d2); // true
-
- // Do they occur on the same hour?
- d1.same().hour(d2); // false, unless d2 hour is '00' (midnight).
-
- // What if it's the same day, but one year apart?
- var nextYear = Date.today().add(1).year();
-
- d1.same().day(nextYear); // false, because the dates must occur on the exact same day.
- </code></pre>
- *
- * Scenario: Determine if a given date occurs during some week period 2 months from now.
- *
- * Example
- <pre><code>
- var future = Date.today().add(2).months();
- return someDate.same().week(future); // true|false;
- </code></pre>
- *
- * @return {Boolean} true|false
- */
- $P.same = function () {
- this._same = true;
- this._isSecond = false;
- return this;
- };
-
- /**
- * Determines if the current date/time occurs during Today. Must be preceded by the .is() function.
- * Example
- <pre><code>
- someDate.is().today(); // true|false
- new Date().is().today(); // true
- Date.today().is().today();// true
- Date.today().add(-1).day().is().today(); // false
- </code></pre>
- *
- * @return {Boolean} true|false
- */
- $P.today = function () {
- return this.same().day();
- };
-
- /**
- * Determines if the current date is a weekday. This function must be preceded by the .is() function.
- * Example
- <pre><code>
- Date.today().is().weekday(); // true|false
- </code></pre>
- *
- * @return {Boolean} true|false
- */
- $P.weekday = function () {
- if (this._is) {
- this._is = false;
- return (!this.is().sat() && !this.is().sun());
- }
- return false;
- };
-
- /**
- * Sets the Time of the current Date instance. A string "6:15 pm" or config object {hour:18, minute:15} are accepted.
- * Example
- <pre><code>
- // Set time to 6:15pm with a String
- Date.today().at("6:15pm");
-
- // Set time to 6:15pm with a config object
- Date.today().at({hour:18, minute:15});
- </code></pre>
- *
- * @return {Date} date
- */
- $P.at = function (time) {
- return (typeof time === "string") ? $D.parse(this.toString("d") + " " + time) : this.set(time);
- };
-
- /**
- * Creates a new Date() and adds this (Number) to the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
- * Example
- <pre><code>
- // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
- (3).days().fromNow();
- (6).months().fromNow();
-
- // Declared Number variables do not require parentheses.
- var n = 6;
- n.months().fromNow();
- </code></pre>
- *
- * @return {Date} A new Date instance
- */
- $N.fromNow = $N.after = function (date) {
- var c = {};
- c[this._dateElement] = this;
- return ((!date) ? new Date() : date.clone()).add(c);
- };
-
- /**
- * Creates a new Date() and subtract this (Number) from the date based on the preceding date element function (eg. second|minute|hour|day|month|year).
- * Example
- <pre><code>
- // Undeclared Numbers must be wrapped with parentheses. Requirment of JavaScript.
- (3).days().ago();
- (6).months().ago();
-
- // Declared Number variables do not require parentheses.
- var n = 6;
- n.months().ago();
- </code></pre>
- *
- * @return {Date} A new Date instance
- */
- $N.ago = $N.before = function (date) {
- var c = {};
- c[this._dateElement] = this * -1;
- return ((!date) ? new Date() : date.clone()).add(c);
- };
-
- // Do NOT modify the following string tokens. These tokens are used to build dynamic functions.
- // All culture-specific strings can be found in the CultureInfo files. See /trunk/src/globalization/.
- var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
- mx = ("january february march april may june july august september october november december").split(/\s/),
- px = ("Millisecond Second Minute Hour Day Week Month Year").split(/\s/),
- pxf = ("Milliseconds Seconds Minutes Hours Date Week Month FullYear").split(/\s/),
- nth = ("final first second third fourth fifth").split(/\s/),
- de;
-
- /**
- * Returns an object literal of all the date parts.
- * Example
- <pre><code>
- var o = new Date().toObject();
-
- // { year: 2008, month: 4, week: 20, day: 13, hour: 18, minute: 9, second: 32, millisecond: 812 }
-
- // The object properties can be referenced directly from the object.
-
- alert(o.day); // alerts "13"
- alert(o.year); // alerts "2008"
- </code></pre>
- *
- * @return {Date} An object literal representing the original date object.
- */
- $P.toObject = function () {
- var o = {};
- for (var i = 0; i < px.length; i++) {
- o[px[i].toLowerCase()] = this["get" + pxf[i]]();
- }
- return o;
- };
-
- /**
- * Returns a date created from an object literal. Ignores the .week property if set in the config.
- * Example
- <pre><code>
- var o = new Date().toObject();
-
- return Date.fromObject(o); // will return the same date.
-
- var o2 = {month: 1, day: 20, hour: 18}; // birthday party!
- Date.fromObject(o2);
- </code></pre>
- *
- * @return {Date} An object literal representing the original date object.
- */
- $D.fromObject = function(config) {
- config.week = null;
- return Date.today().set(config);
- };
-
- // Create day name functions and abbreviated day name functions (eg. monday(), friday(), fri()).
- var df = function (n) {
- return function () {
- if (this._is) {
- this._is = false;
- return this.getDay() == n;
- }
- if (this._nth !== null) {
- // If the .second() function was called earlier, remove the _orient
- // from the date, and then continue.
- // This is required because 'second' can be used in two different context.
- //
- // Example
- //
- // Date.today().add(1).second();
- // Date.march().second().monday();
- //
- // Things get crazy with the following...
- // Date.march().add(1).second().second().monday(); // but it works!!
- //
- if (this._isSecond) {
- this.addSeconds(this._orient * -1);
- }
- // make sure we reset _isSecond
- this._isSecond = false;
-
- var ntemp = this._nth;
- this._nth = null;
- var temp = this.clone().moveToLastDayOfMonth();
- this.moveToNthOccurrence(n, ntemp);
- if (this > temp) {
- throw new RangeError($D.getDayName(n) + " does not occur " + ntemp + " times in the month of " + $D.getMonthName(temp.getMonth()) + " " + temp.getFullYear() + ".");
- }
- return this;
- }
- return this.moveToDayOfWeek(n, this._orient);
- };
- };
-
- var sdf = function (n) {
- return function () {
- var t = $D.today(), shift = n - t.getDay();
- if (n === 0 && $C.firstDayOfWeek === 1 && t.getDay() !== 0) {
- shift = shift + 7;
- }
- return t.addDays(shift);
- };
- };
-
- for (var i = 0; i < dx.length; i++) {
- // Create constant static Day Name variables. Example: Date.MONDAY or Date.MON
- $D[dx[i].toUpperCase()] = $D[dx[i].toUpperCase().substring(0, 3)] = i;
-
- // Create Day Name functions. Example: Date.monday() or Date.mon()
- $D[dx[i]] = $D[dx[i].substring(0, 3)] = sdf(i);
-
- // Create Day Name instance functions. Example: Date.today().next().monday()
- $P[dx[i]] = $P[dx[i].substring(0, 3)] = df(i);
- }
-
- // Create month name functions and abbreviated month name functions (eg. january(), march(), mar()).
- var mf = function (n) {
- return function () {
- if (this._is) {
- this._is = false;
- return this.getMonth() === n;
- }
- return this.moveToMonth(n, this._orient);
- };
- };
-
- var smf = function (n) {
- return function () {
- return $D.today().set({ month: n, day: 1 });
- };
- };
-
- for (var j = 0; j < mx.length; j++) {
- // Create constant static Month Name variables. Example: Date.MARCH or Date.MAR
- $D[mx[j].toUpperCase()] = $D[mx[j].toUpperCase().substring(0, 3)] = j;
-
- // Create Month Name functions. Example: Date.march() or Date.mar()
- $D[mx[j]] = $D[mx[j].substring(0, 3)] = smf(j);
-
- // Create Month Name instance functions. Example: Date.today().next().march()
- $P[mx[j]] = $P[mx[j].substring(0, 3)] = mf(j);
- }
-
- // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
- var ef = function (j) {
- return function () {
- // if the .second() function was called earlier, the _orient
- // has alread been added. Just return this and reset _isSecond.
- if (this._isSecond) {
- this._isSecond = false;
- return this;
- }
-
- if (this._same) {
- this._same = this._is = false;
- var o1 = this.toObject(),
- o2 = (arguments[0] || new Date()).toObject(),
- v = "",
- k = j.toLowerCase();
-
- for (var m = (px.length - 1); m > -1; m--) {
- v = px[m].toLowerCase();
- if (o1[v] != o2[v]) {
- return false;
- }
- if (k == v) {
- break;
- }
- }
- return true;
- }
-
- if (j.substring(j.length - 1) != "s") {
- j += "s";
- }
- return this["add" + j](this._orient);
- };
- };
-
-
- var nf = function (n) {
- return function () {
- this._dateElement = n;
- return this;
- };
- };
-
- for (var k = 0; k < px.length; k++) {
- de = px[k].toLowerCase();
-
- // Create date element functions and plural date element functions used with Date (eg. day(), days(), months()).
- $P[de] = $P[de + "s"] = ef(px[k]);
-
- // Create date element functions and plural date element functions used with Number (eg. day(), days(), months()).
- $N[de] = $N[de + "s"] = nf(de);
- }
-
- $P._ss = ef("Second");
-
- var nthfn = function (n) {
- return function (dayOfWeek) {
- if (this._same) {
- return this._ss(arguments[0]);
- }
- if (dayOfWeek || dayOfWeek === 0) {
- return this.moveToNthOccurrence(dayOfWeek, n);
- }
- this._nth = n;
-
- // if the operator is 'second' add the _orient, then deal with it later...
- if (n === 2 && (dayOfWeek === undefined || dayOfWeek === null)) {
- this._isSecond = true;
- return this.addSeconds(this._orient);
- }
- return this;
- };
- };
-
- for (var l = 0; l < nth.length; l++) {
- $P[nth[l]] = (l === 0) ? nthfn(-1) : nthfn(l);
- }
-}());/**
- * @version: 1.0 Alpha-1
- * @author: Coolite Inc. http://www.coolite.com/
- * @date: 2008-04-13
- * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
- * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
- * @website: http://www.datejs.com/
- */
-
-(function () {
- Date.Parsing = {
- Exception: function (s) {
- this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
- }
- };
-
- var $P = Date.Parsing;
- var _ = $P.Operators = {
- //
- // Tokenizers
- //
- rtoken: function (r) { // regex token
- return function (s) {
- var mx = s.match(r);
- if (mx) {
- return ([ mx[0], s.substring(mx[0].length) ]);
- } else {
- throw new $P.Exception(s);
- }
- };
- },
- token: function (s) { // whitespace-eating token
- return function (s) {
- return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s);
- // Removed .strip()
- // return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s).strip();
- };
- },
- stoken: function (s) { // string token
- return _.rtoken(new RegExp("^" + s));
- },
-
- //
- // Atomic Operators
- //
-
- until: function (p) {
- return function (s) {
- var qx = [], rx = null;
- while (s.length) {
- try {
- rx = p.call(this, s);
- } catch (e) {
- qx.push(rx[0]);
- s = rx[1];
- continue;
- }
- break;
- }
- return [ qx, s ];
- };
- },
- many: function (p) {
- return function (s) {
- var rx = [], r = null;
- while (s.length) {
- try {
- r = p.call(this, s);
- } catch (e) {
- return [ rx, s ];
- }
- rx.push(r[0]);
- s = r[1];
- }
- return [ rx, s ];
- };
- },
-
- // generator operators -- see below
- optional: function (p) {
- return function (s) {
- var r = null;
- try {
- r = p.call(this, s);
- } catch (e) {
- return [ null, s ];
- }
- return [ r[0], r[1] ];
- };
- },
- not: function (p) {
- return function (s) {
- try {
- p.call(this, s);
- } catch (e) {
- return [null, s];
- }
- throw new $P.Exception(s);
- };
- },
- ignore: function (p) {
- return p ?
- function (s) {
- var r = null;
- r = p.call(this, s);
- return [null, r[1]];
- } : null;
- },
- product: function () {
- var px = arguments[0],
- qx = Array.prototype.slice.call(arguments, 1), rx = [];
- for (var i = 0 ; i < px.length ; i++) {
- rx.push(_.each(px[i], qx));
- }
- return rx;
- },
- cache: function (rule) {
- var cache = {}, r = null;
- return function (s) {
- try {
- r = cache[s] = (cache[s] || rule.call(this, s));
- } catch (e) {
- r = cache[s] = e;
- }
- if (r instanceof $P.Exception) {
- throw r;
- } else {
- return r;
- }
- };
- },
-
- // vector operators -- see below
- any: function () {
- var px = arguments;
- return function (s) {
- var r = null;
- for (var i = 0; i < px.length; i++) {
- if (px[i] == null) {
- continue;
- }
- try {
- r = (px[i].call(this, s));
- } catch (e) {
- r = null;
- }
- if (r) {
- return r;
- }
- }
- throw new $P.Exception(s);
- };
- },
- each: function () {
- var px = arguments;
- return function (s) {
- var rx = [], r = null;
- for (var i = 0; i < px.length ; i++) {
- if (px[i] == null) {
- continue;
- }
- try {
- r = (px[i].call(this, s));
- } catch (e) {
- throw new $P.Exception(s);
- }
- rx.push(r[0]);
- s = r[1];
- }
- return [ rx, s];
- };
- },
- all: function () {
- var px = arguments, _ = _;
- return _.each(_.optional(px));
- },
-
- // delimited operators
- sequence: function (px, d, c) {
- d = d || _.rtoken(/^\s*/);
- c = c || null;
-
- if (px.length == 1) {
- return px[0];
- }
- return function (s) {
- var r = null, q = null;
- var rx = [];
- for (var i = 0; i < px.length ; i++) {
- try {
- r = px[i].call(this, s);
- } catch (e) {
- break;
- }
- rx.push(r[0]);
- try {
- q = d.call(this, r[1]);
- } catch (ex) {
- q = null;
- break;
- }
- s = q[1];
- }
- if (!r) {
- throw new $P.Exception(s);
- }
- if (q) {
- throw new $P.Exception(q[1]);
- }
- if (c) {
- try {
- r = c.call(this, r[1]);
- } catch (ey) {
- throw new $P.Exception(r[1]);
- }
- }
- return [ rx, (r?r[1]:s) ];
- };
- },
-
- //
- // Composite Operators
- //
-
- between: function (d1, p, d2) {
- d2 = d2 || d1;
- var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
- return function (s) {
- var rx = _fn.call(this, s);
- return [[rx[0][0], r[0][2]], rx[1]];
- };
- },
- list: function (p, d, c) {
- d = d || _.rtoken(/^\s*/);
- c = c || null;
- return (p instanceof Array ?
- _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) :
- _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
- },
- set: function (px, d, c) {
- d = d || _.rtoken(/^\s*/);
- c = c || null;
- return function (s) {
- // r is the current match, best the current 'best' match
- // which means it parsed the most amount of input
- var r = null, p = null, q = null, rx = null, best = [[], s], last = false;
-
- // go through the rules in the given set
- for (var i = 0; i < px.length ; i++) {
-
- // last is a flag indicating whether this must be the last element
- // if there is only 1 element, then it MUST be the last one
- q = null;
- p = null;
- r = null;
- last = (px.length == 1);
-
- // first, we try simply to match the current pattern
- // if not, try the next pattern
- try {
- r = px[i].call(this, s);
- } catch (e) {
- continue;
- }
-
- // since we are matching against a set of elements, the first
- // thing to do is to add r[0] to matched elements
- rx = [[r[0]], r[1]];
-
- // if we matched and there is still input to parse and
- // we don't already know this is the last element,
- // we're going to next check for the delimiter ...
- // if there's none, or if there's no input left to parse
- // than this must be the last element after all ...
- if (r[1].length > 0 && ! last) {
- try {
- q = d.call(this, r[1]);
- } catch (ex) {
- last = true;
- }
- } else {
- last = true;
- }
-
- // if we parsed the delimiter and now there's no more input,
- // that means we shouldn't have parsed the delimiter at all
- // so don't update r and mark this as the last element ...
- if (!last && q[1].length === 0) {
- last = true;
- }
-
-
- // so, if this isn't the last element, we're going to see if
- // we can get any more matches from the remaining (unmatched)
- // elements ...
- if (!last) {
-
- // build a list of the remaining rules we can match against,
- // i.e., all but the one we just matched against
- var qx = [];
- for (var j = 0; j < px.length ; j++) {
- if (i != j) {
- qx.push(px[j]);
- }
- }
-
- // now invoke recursively set with the remaining input
- // note that we don't include the closing delimiter ...
- // we'll check for that ourselves at the end
- p = _.set(qx, d).call(this, q[1]);
-
- // if we got a non-empty set as a result ...
- // (otw rx already contains everything we want to match)
- if (p[0].length > 0) {
- // update current result, which is stored in rx ...
- // basically, pick up the remaining text from p[1]
- // and concat the result from p[0] so that we don't
- // get endless nesting ...
- rx[0] = rx[0].concat(p[0]);
- rx[1] = p[1];
- }
- }
-
- // at this point, rx either contains the last matched element
- // or the entire matched set that starts with this element.
-
- // now we just check to see if this variation is better than
- // our best so far, in terms of how much of the input is parsed
- if (rx[1].length < best[1].length) {
- best = rx;
- }
-
- // if we've parsed all the input, then we're finished
- if (best[1].length === 0) {
- break;
- }
- }
-
- // so now we've either gone through all the patterns trying them
- // as the initial match; or we found one that parsed the entire
- // input string ...
-
- // if best has no matches, just return empty set ...
- if (best[0].length === 0) {
- return best;
- }
-
- // if a closing delimiter is provided, then we have to check it also
- if (c) {
- // we try this even if there is no remaining input because the pattern
- // may well be optional or match empty input ...
- try {
- q = c.call(this, best[1]);
- } catch (ey) {
- throw new $P.Exception(best[1]);
- }
-
- // it parsed ... be sure to update the best match remaining input
- best[1] = q[1];
- }
-
- // if we're here, either there was no closing delimiter or we parsed it
- // so now we have the best match; just return it!
- return best;
- };
- },
- forward: function (gr, fname) {
- return function (s) {
- return gr[fname].call(this, s);
- };
- },
-
- //
- // Translation Operators
- //
- replace: function (rule, repl) {
- return function (s) {
- var r = rule.call(this, s);
- return [repl, r[1]];
- };
- },
- process: function (rule, fn) {
- return function (s) {
- var r = rule.call(this, s);
- return [fn.call(this, r[0]), r[1]];
- };
- },
- min: function (min, rule) {
- return function (s) {
- var rx = rule.call(this, s);
- if (rx[0].length < min) {
- throw new $P.Exception(s);
- }
- return rx;
- };
- }
- };
-
-
- // Generator Operators And Vector Operators
-
- // Generators are operators that have a signature of F(R) => R,
- // taking a given rule and returning another rule, such as
- // ignore, which parses a given rule and throws away the result.
-
- // Vector operators are those that have a signature of F(R1,R2,...) => R,
- // take a list of rules and returning a new rule, such as each.
-
- // Generator operators are converted (via the following _generator
- // function) into functions that can also take a list or array of rules
- // and return an array of new rules as though the function had been
- // called on each rule in turn (which is what actually happens).
-
- // This allows generators to be used with vector operators more easily.
- // Example:
- // each(ignore(foo, bar)) instead of each(ignore(foo), ignore(bar))
-
- // This also turns generators into vector operators, which allows
- // constructs like:
- // not(cache(foo, bar))
-
- var _generator = function (op) {
- return function () {
- var args = null, rx = [];
- if (arguments.length > 1) {
- args = Array.prototype.slice.call(arguments);
- } else if (arguments[0] instanceof Array) {
- args = arguments[0];
- }
- if (args) {
- for (var i = 0, px = args.shift() ; i < px.length ; i++) {
- args.unshift(px[i]);
- rx.push(op.apply(null, args));
- args.shift();
- return rx;
- }
- } else {
- return op.apply(null, arguments);
- }
- };
- };
-
- var gx = "optional not ignore cache".split(/\s/);
-
- for (var i = 0 ; i < gx.length ; i++) {
- _[gx[i]] = _generator(_[gx[i]]);
- }
-
- var _vector = function (op) {
- return function () {
- if (arguments[0] instanceof Array) {
- return op.apply(null, arguments[0]);
- } else {
- return op.apply(null, arguments);
- }
- };
- };
-
- var vx = "each any all".split(/\s/);
-
- for (var j = 0 ; j < vx.length ; j++) {
- _[vx[j]] = _vector(_[vx[j]]);
- }
-
-}());
-
-(function () {
- var $D = Date, $P = $D.prototype, $C = $D.CultureInfo;
-
- var flattenAndCompact = function (ax) {
- var rx = [];
- for (var i = 0; i < ax.length; i++) {
- if (ax[i] instanceof Array) {
- rx = rx.concat(flattenAndCompact(ax[i]));
- } else {
- if (ax[i]) {
- rx.push(ax[i]);
- }
- }
- }
- return rx;
- };
-
- $D.Grammar = {};
-
- $D.Translator = {
- hour: function (s) {
- return function () {
- this.hour = Number(s);
- };
- },
- minute: function (s) {
- return function () {
- this.minute = Number(s);
- };
- },
- second: function (s) {
- return function () {
- this.second = Number(s);
- };
- },
- meridian: function (s) {
- return function () {
- this.meridian = s.slice(0, 1).toLowerCase();
- };
- },
- timezone: function (s) {
- return function () {
- var n = s.replace(/[^\d\+\-]/g, "");
- if (n.length) {
- this.timezoneOffset = Number(n);
- } else {
- this.timezone = s.toLowerCase();
- }
- };
- },
- day: function (x) {
- var s = x[0];
- return function () {
- this.day = Number(s.match(/\d+/)[0]);
- };
- },
- month: function (s) {
- return function () {
- this.month = (s.length == 3) ? "jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4 : Number(s) - 1;
- };
- },
- year: function (s) {
- return function () {
- var n = Number(s);
- this.year = ((s.length > 2) ? n :
- (n + (((n + 2000) < $C.twoDigitYearMax) ? 2000 : 1900)));
- };
- },
- rday: function (s) {
- return function () {
- switch (s) {
- case "yesterday":
- this.days = -1;
- break;
- case "tomorrow":
- this.days = 1;
- break;
- case "today":
- this.days = 0;
- break;
- case "now":
- this.days = 0;
- this.now = true;
- break;
- }
- };
- },
- finishExact: function (x) {
- x = (x instanceof Array) ? x : [ x ];
-
- for (var i = 0 ; i < x.length ; i++) {
- if (x[i]) {
- x[i].call(this);
- }
- }
-
- var now = new Date();
-
- if ((this.hour || this.minute) && (!this.month && !this.year && !this.day)) {
- this.day = now.getDate();
- }
-
- if (!this.year) {
- this.year = now.getFullYear();
- }
-
- if (!this.month && this.month !== 0) {
- this.month = now.getMonth();
- }
-
- if (!this.day) {
- this.day = 1;
- }
-
- if (!this.hour) {
- this.hour = 0;
- }
-
- if (!this.minute) {
- this.minute = 0;
- }
-
- if (!this.second) {
- this.second = 0;
- }
-
- if (this.meridian && this.hour) {
- if (this.meridian == "p" && this.hour < 12) {
- this.hour = this.hour + 12;
- } else if (this.meridian == "a" && this.hour == 12) {
- this.hour = 0;
- }
- }
-
- if (this.day > $D.getDaysInMonth(this.year, this.month)) {
- throw new RangeError(this.day + " is not a valid value for days.");
- }
-
- var r = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second);
-
- if (this.timezone) {
- r.set({ timezone: this.timezone });
- } else if (this.timezoneOffset) {
- r.set({ timezoneOffset: this.timezoneOffset });
- }
-
- return r;
- },
- finish: function (x) {
- x = (x instanceof Array) ? flattenAndCompact(x) : [ x ];
-
- if (x.length === 0) {
- return null;
- }
-
- for (var i = 0 ; i < x.length ; i++) {
- if (typeof x[i] == "function") {
- x[i].call(this);
- }
- }
-
- var today = $D.today();
-
- if (this.now && !this.unit && !this.operator) {
- return new Date();
- } else if (this.now) {
- today = new Date();
- }
-
- var expression = !!(this.days && this.days !== null || this.orient || this.operator);
-
- var gap, mod, orient;
- orient = ((this.orient == "past" || this.operator == "subtract") ? -1 : 1);
-
- if(!this.now && "hour minute second".indexOf(this.unit) != -1) {
- today.setTimeToNow();
- }
-
- if (this.month || this.month === 0) {
- if ("year day hour minute second".indexOf(this.unit) != -1) {
- this.value = this.month + 1;
- this.month = null;
- expression = true;
- }
- }
-
- if (!expression && this.weekday && !this.day && !this.days) {
- var temp = Date[this.weekday]();
- this.day = temp.getDate();
- if (!this.month) {
- this.month = temp.getMonth();
- }
- this.year = temp.getFullYear();
- }
-
- if (expression && this.weekday && this.unit != "month") {
- this.unit = "day";
- gap = ($D.getDayNumberFromName(this.weekday) - today.getDay());
- mod = 7;
- this.days = gap ? ((gap + (orient * mod)) % mod) : (orient * mod);
- }
-
- if (this.month && this.unit == "day" && this.operator) {
- this.value = (this.month + 1);
- this.month = null;
- }
-
- if (this.value != null && this.month != null && this.year != null) {
- this.day = this.value * 1;
- }
-
- if (this.month && !this.day && this.value) {
- today.set({ day: this.value * 1 });
- if (!expression) {
- this.day = this.value * 1;
- }
- }
-
- if (!this.month && this.value && this.unit == "month" && !this.now) {
- this.month = this.value;
- expression = true;
- }
-
- if (expression && (this.month || this.month === 0) && this.unit != "year") {
- this.unit = "month";
- gap = (this.month - today.getMonth());
- mod = 12;
- this.months = gap ? ((gap + (orient * mod)) % mod) : (orient * mod);
- this.month = null;
- }
-
- if (!this.unit) {
- this.unit = "day";
- }
-
- if (!this.value && this.operator && this.operator !== null && this[this.unit + "s"] && this[this.unit + "s"] !== null) {
- this[this.unit + "s"] = this[this.unit + "s"] + ((this.operator == "add") ? 1 : -1) + (this.value||0) * orient;
- } else if (this[this.unit + "s"] == null || this.operator != null) {
- if (!this.value) {
- this.value = 1;
- }
- this[this.unit + "s"] = this.value * orient;
- }
-
- if (this.meridian && this.hour) {
- if (this.meridian == "p" && this.hour < 12) {
- this.hour = this.hour + 12;
- } else if (this.meridian == "a" && this.hour == 12) {
- this.hour = 0;
- }
- }
-
- if (this.weekday && !this.day && !this.days) {
- var temp = Date[this.weekday]();
- this.day = temp.getDate();
- if (temp.getMonth() !== today.getMonth()) {
- this.month = temp.getMonth();
- }
- }
-
- if ((this.month || this.month === 0) && !this.day) {
- this.day = 1;
- }
-
- if (!this.orient && !this.operator && this.unit == "week" && this.value && !this.day && !this.month) {
- return Date.today().setWeek(this.value);
- }
-
- if (expression && this.timezone && this.day && this.days) {
- this.day = this.days;
- }
-
- return (expression) ? today.add(this) : today.set(this);
- }
- };
-
- var _ = $D.Parsing.Operators, g = $D.Grammar, t = $D.Translator, _fn;
-
- g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
- g.timePartDelimiter = _.stoken(":");
- g.whiteSpace = _.rtoken(/^\s*/);
- g.generalDelimiter = _.rtoken(/^(([\s\,]|at|@|on)+)/);
-
- var _C = {};
- g.ctoken = function (keys) {
- var fn = _C[keys];
- if (! fn) {
- var c = $C.regexPatterns;
- var kx = keys.split(/\s+/), px = [];
- for (var i = 0; i < kx.length ; i++) {
- px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
- }
- fn = _C[keys] = _.any.apply(null, px);
- }
- return fn;
- };
- g.ctoken2 = function (key) {
- return _.rtoken($C.regexPatterns[key]);
- };
-
- // hour, minute, second, meridian, timezone
- g.h = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/), t.hour));
- g.hh = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/), t.hour));
- g.H = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/), t.hour));
- g.HH = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/), t.hour));
- g.m = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.minute));
- g.mm = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.minute));
- g.s = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.second));
- g.ss = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.second));
- g.hms = _.cache(_.sequence([g.H, g.m, g.s], g.timePartDelimiter));
-
- // _.min(1, _.set([ g.H, g.m, g.s ], g._t));
- g.t = _.cache(_.process(g.ctoken2("shortMeridian"), t.meridian));
- g.tt = _.cache(_.process(g.ctoken2("longMeridian"), t.meridian));
- g.z = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone));
- g.zz = _.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/), t.timezone));
-
- g.zzz = _.cache(_.process(g.ctoken2("timezone"), t.timezone));
- g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([ g.tt, g.zzz ]));
- g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
-
- // days, months, years
- g.d = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/),
- _.optional(g.ctoken2("ordinalSuffix"))), t.day));
- g.dd = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/),
- _.optional(g.ctoken2("ordinalSuffix"))), t.day));
- g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),
- function (s) {
- return function () {
- this.weekday = s;
- };
- }
- ));
- g.M = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/), t.month));
- g.MM = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/), t.month));
- g.MMM = g.MMMM = _.cache(_.process(
- g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
- g.y = _.cache(_.process(_.rtoken(/^(\d\d?)/), t.year));
- g.yy = _.cache(_.process(_.rtoken(/^(\d\d)/), t.year));
- g.yyy = _.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/), t.year));
- g.yyyy = _.cache(_.process(_.rtoken(/^(\d\d\d\d)/), t.year));
-
- // rolling these up into general purpose rules
- _fn = function () {
- return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
- };
-
- g.day = _fn(g.d, g.dd);
- g.month = _fn(g.M, g.MMM);
- g.year = _fn(g.yyyy, g.yy);
-
- // relative date / time expressions
- g.orientation = _.process(g.ctoken("past future"),
- function (s) {
- return function () {
- this.orient = s;
- };
- }
- );
- g.operator = _.process(g.ctoken("add subtract"),
- function (s) {
- return function () {
- this.operator = s;
- };
- }
- );
- g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
- g.unit = _.process(g.ctoken("second minute hour day week month year"),
- function (s) {
- return function () {
- this.unit = s;
- };
- }
- );
- g.value = _.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/),
- function (s) {
- return function () {
- this.value = s.replace(/\D/g, "");
- };
- }
- );
- g.expression = _.set([ g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM ]);
-
- // pre-loaded rules for different date part order preferences
- _fn = function () {
- return _.set(arguments, g.datePartDelimiter);
- };
- g.mdy = _fn(g.ddd, g.month, g.day, g.year);
- g.ymd = _fn(g.ddd, g.year, g.month, g.day);
- g.dmy = _fn(g.ddd, g.day, g.month, g.year);
- g.date = function (s) {
- return ((g[$C.dateElementOrder] || g.mdy).call(this, s));
- };
-
- // parsing date format specifiers - ex: "h:m:s tt"
- // this little guy will generate a custom parser based
- // on the format string, ex: g.format("h:m:s tt")
- g.format = _.process(_.many(
- _.any(
- // translate format specifiers into grammar rules
- _.process(
- _.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),
- function (fmt) {
- if (g[fmt]) {
- return g[fmt];
- } else {
- throw $D.Parsing.Exception(fmt);
- }
- }
- ),
- // translate separator tokens into token rules
- _.process(
- _.rtoken(/^[^dMyhHmstz]+/), // all legal separators
- function (s) {
- return _.ignore(_.stoken(s));
- }
- )
- )),
- // construct the parser ...
- function (rules) {
- return _.process(_.each.apply(null, rules), t.finishExact);
- }
- );
-
- var _F = {
- //"M/d/yyyy": function (s) {
- // var m = s.match(/^([0-2]\d|3[0-1]|\d)\/(1[0-2]|0\d|\d)\/(\d\d\d\d)/);
- // if (m!=null) {
- // var r = [ t.month.call(this,m[1]), t.day.call(this,m[2]), t.year.call(this,m[3]) ];
- // r = t.finishExact.call(this,r);
- // return [ r, "" ];
- // } else {
- // throw new Date.Parsing.Exception(s);
- // }
- //}
- //"M/d/yyyy": function (s) { return [ new Date(Date._parse(s)), ""]; }
- };
- var _get = function (f) {
- return _F[f] = (_F[f] || g.format(f)[0]);
- };
-
- g.formats = function (fx) {
- if (fx instanceof Array) {
- var rx = [];
- for (var i = 0 ; i < fx.length ; i++) {
- rx.push(_get(fx[i]));
- }
- return _.any.apply(null, rx);
- } else {
- return _get(fx);
- }
- };
-
- // check for these formats first
- g._formats = g.formats([
- "\"yyyy-MM-ddTHH:mm:ssZ\"",
- "yyyy-MM-ddTHH:mm:ssZ",
- "yyyy-MM-ddTHH:mm:ssz",
- "yyyy-MM-ddTHH:mm:ss",
- "yyyy-MM-ddTHH:mmZ",
- "yyyy-MM-ddTHH:mmz",
- "yyyy-MM-ddTHH:mm",
- "ddd, MMM dd, yyyy H:mm:ss tt",
- "ddd MMM d yyyy HH:mm:ss zzz",
- "MMddyyyy",
- "ddMMyyyy",
- "Mddyyyy",
- "ddMyyyy",
- "Mdyyyy",
- "dMyyyy",
- "yyyy",
- "Mdyy",
- "dMyy",
- "d"
- ]);
-
- // starting rule for general purpose grammar
- g._start = _.process(_.set([ g.date, g.time, g.expression ],
- g.generalDelimiter, g.whiteSpace), t.finish);
-
- // real starting rule: tries selected formats first,
- // then general purpose rule
- g.start = function (s) {
- try {
- var r = g._formats.call({}, s);
- if (r[1].length === 0) {
- return r;
- }
- } catch (e) {}
- return g._start.call({}, s);
- };
-
- $D._parse = $D.parse;
-
- /**
- * Converts the specified string value into its JavaScript Date equivalent using CultureInfo specific format information.
- *
- * Example
- <pre><code>
- ///////////
- // Dates //
- ///////////
-
- // 15-Oct-2004
- var d1 = Date.parse("10/15/2004");
-
- // 15-Oct-2004
- var d1 = Date.parse("15-Oct-2004");
-
- // 15-Oct-2004
- var d1 = Date.parse("2004.10.15");
-
- //Fri Oct 15, 2004
- var d1 = Date.parse("Fri Oct 15, 2004");
-
- ///////////
- // Times //
- ///////////
-
- // Today at 10 PM.
- var d1 = Date.parse("10 PM");
-
- // Today at 10:30 PM.
- var d1 = Date.parse("10:30 P.M.");
-
- // Today at 6 AM.
- var d1 = Date.parse("06am");
-
- /////////////////////
- // Dates and Times //
- /////////////////////
-
- // 8-July-2004 @ 10:30 PM
- var d1 = Date.parse("July 8th, 2004, 10:30 PM");
-
- // 1-July-2004 @ 10:30 PM
- var d1 = Date.parse("2004-07-01T22:30:00");
-
- ////////////////////
- // Relative Dates //
- ////////////////////
-
- // Returns today's date. The string "today" is culture specific.
- var d1 = Date.parse("today");
-
- // Returns yesterday's date. The string "yesterday" is culture specific.
- var d1 = Date.parse("yesterday");
-
- // Returns the date of the next thursday.
- var d1 = Date.parse("Next thursday");
-
- // Returns the date of the most previous monday.
- var d1 = Date.parse("last monday");
-
- // Returns today's day + one year.
- var d1 = Date.parse("next year");
-
- ///////////////
- // Date Math //
- ///////////////
-
- // Today + 2 days
- var d1 = Date.parse("t+2");
-
- // Today + 2 days
- var d1 = Date.parse("today + 2 days");
-
- // Today + 3 months
- var d1 = Date.parse("t+3m");
-
- // Today - 1 year
- var d1 = Date.parse("today - 1 year");
-
- // Today - 1 year
- var d1 = Date.parse("t-1y");
-
-
- /////////////////////////////
- // Partial Dates and Times //
- /////////////////////////////
-
- // July 15th of this year.
- var d1 = Date.parse("July 15");
-
- // 15th day of current day and year.
- var d1 = Date.parse("15");
-
- // July 1st of current year at 10pm.
- var d1 = Date.parse("7/1 10pm");
- </code></pre>
- *
- * @param {String} The string value to convert into a Date object [Required]
- * @return {Date} A Date object or null if the string cannot be converted into a Date.
- */
- $D.parse = function (s) {
- var r = null;
- if (!s) {
- return null;
- }
- if (s instanceof Date) {
- return s;
- }
- try {
- r = $D.Grammar.start.call({}, s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
- } catch (e) {
- return null;
- }
- return ((r[1].length === 0) ? r[0] : null);
- };
-
- $D.getParseFunction = function (fx) {
- var fn = $D.Grammar.formats(fx);
- return function (s) {
- var r = null;
- try {
- r = fn.call({}, s);
- } catch (e) {
- return null;
- }
- return ((r[1].length === 0) ? r[0] : null);
- };
- };
-
- /**
- * Converts the specified string value into its JavaScript Date equivalent using the specified format {String} or formats {Array} and the CultureInfo specific format information.
- * The format of the string value must match one of the supplied formats exactly.
- *
- * Example
- <pre><code>
- // 15-Oct-2004
- var d1 = Date.parseExact("10/15/2004", "M/d/yyyy");
-
- // 15-Oct-2004
- var d1 = Date.parse("15-Oct-2004", "M-ddd-yyyy");
-
- // 15-Oct-2004
- var d1 = Date.parse("2004.10.15", "yyyy.MM.dd");
-
- // Multiple formats
- var d1 = Date.parseExact("10/15/2004", ["M/d/yyyy", "MMMM d, yyyy"]);
- </code></pre>
- *
- * @param {String} The string value to convert into a Date object [Required].
- * @param {Object} The expected format {String} or an array of expected formats {Array} of the date string [Required].
- * @return {Date} A Date object or null if the string cannot be converted into a Date.
- */
- $D.parseExact = function (s, fx) {
- return $D.getParseFunction(fx)(s);
- };
-}());
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "de-DE",
- englishName: "German (Germany)",
- nativeName: "Deutsch (Deutschland)",
-
- /* Day Name Strings */
- dayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
- abbreviatedDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
- shortestDayNames: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
- firstLetterDayNames: ["S", "M", "D", "M", "D", "F", "S"],
-
- /* Month Name Strings */
- monthNames: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
- abbreviatedMonthNames: ["Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd.MM.yyyy",
- longDate: "dddd, d. MMMM yyyy",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "dddd, d. MMMM yyyy HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(uar)?/i,
- feb: /^feb(ruar)?/i,
- mar: /^märz/i,
- apr: /^apr(il)?/i,
- may: /^mai/i,
- jun: /^jun(i)?/i,
- jul: /^jul(i)?/i,
- aug: /^aug(ust)?/i,
- sep: /^sep(t(ember)?)?/i,
- oct: /^okt(ober)?/i,
- nov: /^nov(ember)?/i,
- dec: /^dez(ember)?/i,
-
- sun: /^sonntag/i,
- mon: /^montag/i,
- tue: /^dienstag/i,
- wed: /^mittwoch/i,
- thu: /^donnerstag/i,
- fri: /^freitag/i,
- sat: /^samstag/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "el-GR",
- englishName: "Greek (Greece)",
- nativeName: "ελληνικά (Ελλάδα)",
-
- /* Day Name Strings */
- dayNames: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο"],
- abbreviatedDayNames: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ"],
- shortestDayNames: ["Κυ", "Δε", "Τρ", "Τε", "Πε", "Πα", "Σά"],
- firstLetterDayNames: ["Κ", "Δ", "Τ", "Τ", "Π", "Π", "Σ"],
-
- /* Month Name Strings */
- monthNames: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"],
- abbreviatedMonthNames: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαϊ", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"],
-
- /* AM/PM Designators */
- amDesignator: "πμ",
- pmDesignator: "μμ",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "d/M/yyyy",
- longDate: "dddd, d MMMM yyyy",
- shortTime: "h:mm tt",
- longTime: "h:mm:ss tt",
- fullDateTime: "dddd, d MMMM yyyy h:mm:ss tt",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^ιαν(ουάριος)?/i,
- feb: /^φεβ(ρουάριος)?/i,
- mar: /^μάρτιος/i,
- apr: /^απρ(ίλιος)?/i,
- may: /^μάιος/i,
- jun: /^ιούνιος/i,
- jul: /^ιούλιος/i,
- aug: /^αύγουστος/i,
- sep: /^σεπ(τέμβριος)?/i,
- oct: /^οκτ(ώβριος)?/i,
- nov: /^νοέμβριος/i,
- dec: /^δεκ(έμβριος)?/i,
-
- sun: /^κυ(ρ(ιακή)?)?/i,
- mon: /^δε(υ(τέρα)?)?/i,
- tue: /^τρ(ι(τη)?)?/i,
- wed: /^τε(τ(άρτη)?)?/i,
- thu: /^πε(μ(πτη)?)?/i,
- fri: /^πα(ρ(ασκευή)?)?/i,
- sat: /^σά(β(βατο)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Event.observe(window, 'load', function() {
- var nodeCount = kronolithNodes.length;
- for (var n = 0; n < nodeCount; n++) {
- var j = kronolithNodes[n];
- $(j).update(kronolith[j]);
- if (typeof Horde_ToolTips != 'undefined') {
- // Need a closure here to ensure we preserve the value of j during
- // each loop iteration.
- (function() {
- var jx = j;
- Horde_ToolTips.attachBehavior(jx);
- })();
- }
- }
- Event.observe(window, 'unload', Horde_ToolTips.out.bind(Horde_ToolTips));
-});
\ No newline at end of file
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "en-US",
- englishName: "English (United States)",
- nativeName: "English (United States)",
-
- /* Day Name Strings */
- dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
- abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
- shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
- firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
-
- /* Month Name Strings */
- monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
- abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
-
- /* AM/PM Designators */
- amDesignator: "AM",
- pmDesignator: "PM",
-
- firstDayOfWeek: 0,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "mdy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "M/d/yyyy",
- longDate: "dddd, MMMM dd, yyyy",
- shortTime: "h:mm tt",
- longTime: "h:mm:ss tt",
- fullDateTime: "dddd, MMMM dd, yyyy h:mm:ss tt",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "MMMM dd",
- yearMonth: "MMMM, yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(uary)?/i,
- feb: /^feb(ruary)?/i,
- mar: /^mar(ch)?/i,
- apr: /^apr(il)?/i,
- may: /^may/i,
- jun: /^jun(e)?/i,
- jul: /^jul(y)?/i,
- aug: /^aug(ust)?/i,
- sep: /^sep(t(ember)?)?/i,
- oct: /^oct(ober)?/i,
- nov: /^nov(ember)?/i,
- dec: /^dec(ember)?/i,
-
- sun: /^su(n(day)?)?/i,
- mon: /^mo(n(day)?)?/i,
- tue: /^tu(e(s(day)?)?)?/i,
- wed: /^we(d(nesday)?)?/i,
- thu: /^th(u(r(s(day)?)?)?)?/i,
- fri: /^fr(i(day)?)?/i,
- sat: /^sa(t(urday)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "es-ES",
- englishName: "Spanish (Spain)",
- nativeName: "español (España)",
-
- /* Day Name Strings */
- dayNames: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
- abbreviatedDayNames: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
- shortestDayNames: ["do", "lu", "ma", "mi", "ju", "vi", "sá"],
- firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
-
- /* Month Name Strings */
- monthNames: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
- abbreviatedMonthNames: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd/MM/yyyy",
- longDate: "dddd, dd' de 'MMMM' de 'yyyy",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM' de 'yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^ene(ro)?/i,
- feb: /^feb(rero)?/i,
- mar: /^mar(zo)?/i,
- apr: /^abr(il)?/i,
- may: /^may(o)?/i,
- jun: /^jun(io)?/i,
- jul: /^jul(io)?/i,
- aug: /^ago(sto)?/i,
- sep: /^sep(tiembre)?/i,
- oct: /^oct(ubre)?/i,
- nov: /^nov(iembre)?/i,
- dec: /^dic(iembre)?/i,
-
- sun: /^do(m(ingo)?)?/i,
- mon: /^lu(n(es)?)?/i,
- tue: /^ma(r(tes)?)?/i,
- wed: /^mi(é(rcoles)?)?/i,
- thu: /^ju(e(ves)?)?/i,
- fri: /^vi(e(rnes)?)?/i,
- sat: /^sá(b(ado)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "et-EE",
- englishName: "Estonian (Estonia)",
- nativeName: "eesti (Eesti)",
-
- /* Day Name Strings */
- dayNames: ["pühapäev", "esmaspäev", "teisipäev", "kolmapäev", "neljapäev", "reede", "laupäev"],
- abbreviatedDayNames: ["P", "E", "T", "K", "N", "R", "L"],
- shortestDayNames: ["P", "E", "T", "K", "N", "R", "L"],
- firstLetterDayNames: ["P", "E", "T", "K", "N", "R", "L"],
-
- /* Month Name Strings */
- monthNames: ["jaanuar", "veebruar", "märts", "aprill", "mai", "juuni", "juuli", "august", "september", "oktoober", "november", "detsember"],
- abbreviatedMonthNames: ["jaan", "veebr", "märts", "apr", "mai", "juuni", "juuli", "aug", "sept", "okt", "nov", "dets"],
-
- /* AM/PM Designators */
- amDesignator: "EL",
- pmDesignator: "PL",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "d.MM.yyyy",
- longDate: "d. MMMM yyyy'. a.'",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "d. MMMM yyyy'. a.' H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "d. MMMM",
- yearMonth: "MMMM yyyy'. a.'"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jaan(uar)?/i,
- feb: /^veebr(uar)?/i,
- mar: /^märts/i,
- apr: /^apr(ill)?/i,
- may: /^mai/i,
- jun: /^juuni/i,
- jul: /^juuli/i,
- aug: /^aug(ust)?/i,
- sep: /^sep(t(ember)?)?/i,
- oct: /^okt(oober)?/i,
- nov: /^nov(ember)?/i,
- dec: /^dets(ember)?/i,
-
- sun: /^pühapäev/i,
- mon: /^esmaspäev/i,
- tue: /^teisipäev/i,
- wed: /^kolmapäev/i,
- thu: /^neljapäev/i,
- fri: /^reede/i,
- sat: /^laupäev/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "eu-ES",
- englishName: "Basque (Basque)",
- nativeName: "euskara (euskara)",
-
- /* Day Name Strings */
- dayNames: ["igandea", "astelehena", "asteartea", "asteazkena", "osteguna", "ostirala", "larunbata"],
- abbreviatedDayNames: ["ig.", "al.", "as.", "az.", "og.", "or.", "lr."],
- shortestDayNames: ["ig", "al", "as", "az", "og", "or", "lr"],
- firstLetterDayNames: ["i", "a", "a", "a", "o", "o", "l"],
-
- /* Month Name Strings */
- monthNames: ["urtarrila", "otsaila", "martxoa", "apirila", "maiatza", "ekaina", "uztaila", "abuztua", "iraila", "urria", "azaroa", "abendua"],
- abbreviatedMonthNames: ["urt.", "ots.", "mar.", "api.", "mai.", "eka.", "uzt.", "abu.", "ira.", "urr.", "aza.", "abe."],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "ymd",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "yyyy/MM/dd",
- longDate: "dddd, yyyy.'eko' MMMM'k 'd",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "dddd, yyyy.'eko' MMMM'k 'd HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "MMMM dd",
- yearMonth: "yyyy.'eko' MMMM"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^urt(.(arrila)?)?/i,
- feb: /^ots(.(aila)?)?/i,
- mar: /^mar(.(txoa)?)?/i,
- apr: /^api(.(rila)?)?/i,
- may: /^mai(.(atza)?)?/i,
- jun: /^eka(.(ina)?)?/i,
- jul: /^uzt(.(aila)?)?/i,
- aug: /^abu(.(ztua)?)?/i,
- sep: /^ira(.(ila)?)?/i,
- oct: /^urr(.(ia)?)?/i,
- nov: /^aza(.(roa)?)?/i,
- dec: /^abe(.(ndua)?)?/i,
-
- sun: /^ig((.(andea)?)?)?/i,
- mon: /^al((.(telehena)?)?)?/i,
- tue: /^as((.(teartea)?)?)?/i,
- wed: /^az((.(teazkena)?)?)?/i,
- thu: /^og((.(teguna)?)?)?/i,
- fri: /^or((.(tirala)?)?)?/i,
- sat: /^lr((.(runbata)?)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-/**
- * @version: 1.0 Alpha-1
- * @author: Coolite Inc. http://www.coolite.com/
- * @date: 2008-04-13
- * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
- * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
- * @website: http://www.datejs.com/
- */
-
-(function () {
- var $D = Date,
- $P = $D.prototype,
- $C = $D.CultureInfo,
- $f = [],
- p = function (s, l) {
- if (!l) {
- l = 2;
- }
- return ("000" + s).slice(l * -1);
- };
-
- /**
- * Converts a PHP format string to Java/.NET format string.
- * A PHP format string can be used with .$format or .format.
- * A Java/.NET format string can be used with .toString().
- * The .parseExact function will only accept a Java/.NET format string
- *
- * Example
- <pre>
- var f1 = "%m/%d/%y"
- var f2 = Date.normalizeFormat(f1); // "MM/dd/yy"
-
- new Date().format(f1); // "04/13/08"
- new Date().$format(f1); // "04/13/08"
- new Date().toString(f2); // "04/13/08"
-
- var date = Date.parseExact("04/13/08", f2); // Sun Apr 13 2008
- </pre>
- * @param {String} A PHP format string consisting of one or more format spcifiers.
- * @return {String} The PHP format converted to a Java/.NET format string.
- */
- $D.normalizeFormat = function (format) {
- $f = [];
- var t = new Date().$format(format);
- return $f.join("");
- };
-
- /**
- * Format a local Unix timestamp according to locale settings
- *
- * Example
- <pre>
- Date.strftime("%m/%d/%y", new Date()); // "04/13/08"
- Date.strftime("c", "2008-04-13T17:52:03Z"); // "04/13/08"
- </pre>
- * @param {String} A format string consisting of one or more format spcifiers [Optional].
- * @param {Number} The number representing the number of seconds that have elapsed since January 1, 1970 (local time).
- * @return {String} A string representation of the current Date object.
- */
- $D.strftime = function (format, time) {
- return new Date(time * 1000).$format(format);
- };
-
- /**
- * Parse any textual datetime description into a Unix timestamp.
- * A Unix timestamp is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT).
- *
- * Example
- <pre>
- Date.strtotime("04/13/08"); // 1208044800
- Date.strtotime("1970-01-01T00:00:00Z"); // 0
- </pre>
- * @param {String} A format string consisting of one or more format spcifiers [Optional].
- * @param {Object} A string or date object.
- * @return {String} A string representation of the current Date object.
- */
- $D.strtotime = function (time) {
- var d = $D.parse(time);
- d.addMinutes(d.getTimezoneOffset() * -1);
- return Math.round($D.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()) / 1000);
- };
-
- /**
- * Converts the value of the current Date object to its equivalent string representation using a PHP/Unix style of date format specifiers.
- *
- * The following descriptions are from http://www.php.net/strftime and http://www.php.net/manual/en/function.date.php.
- * Copyright © 2001-2008 The PHP Group
- *
- * Format Specifiers
- <pre>
- Format Description Example
- ------ --------------------------------------------------------------------------- -----------------------
- %a abbreviated weekday name according to the current localed "Mon" through "Sun"
- %A full weekday name according to the current locale "Sunday" through "Saturday"
- %b abbreviated month name according to the current locale "Jan" through "Dec"
- %B full month name according to the current locale "January" through "December"
- %c preferred date and time representation for the current locale "4/13/2008 12:33 PM"
- %C century number (the year divided by 100 and truncated to an integer) "00" to "99"
- %d day of the month as a decimal number "01" to "31"
- %D same as %m/%d/%y "04/13/08"
- %e day of the month as a decimal number, a single digit is preceded by a space "1" to "31"
- %g like %G, but without the century "08"
- %G The 4-digit year corresponding to the ISO week number (see %V). "2008"
- This has the same format and value as %Y, except that if the ISO week number
- belongs to the previous or next year, that year is used instead.
- %h same as %b "Jan" through "Dec"
- %H hour as a decimal number using a 24-hour clock "00" to "23"
- %I hour as a decimal number using a 12-hour clock "01" to "12"
- %j day of the year as a decimal number "001" to "366"
- %m month as a decimal number "01" to "12"
- %M minute as a decimal number "00" to "59"
- %n newline character "\n"
- %p either "am" or "pm" according to the given time value, or the "am" or "pm"
- corresponding strings for the current locale
- %r time in a.m. and p.m. notation "8:44 PM"
- %R time in 24 hour notation "20:44"
- %S second as a decimal number "00" to "59"
- %t tab character "\t"
- %T current time, equal to %H:%M:%S "12:49:11"
- %u weekday as a decimal number ["1", "7"], with "1" representing Monday "1" to "7"
- %U week number of the current year as a decimal number, starting with the "0" to ("52" or "53")
- first Sunday as the first day of the first week
- %V The ISO 8601:1988 week number of the current year as a decimal number, "00" to ("52" or "53")
- range 01 to 53, where week 1 is the first week that has at least 4 days
- in the current year, and with Monday as the first day of the week.
- (Use %G or %g for the year component that corresponds to the week number
- for the specified timestamp.)
- %W week number of the current year as a decimal number, starting with the "00" to ("52" or "53")
- first Monday as the first day of the first week
- %w day of the week as a decimal, Sunday being "0" "0" to "6"
- %x preferred date representation for the current locale without the time "4/13/2008"
- %X preferred time representation for the current locale without the date "12:53:05"
- %y year as a decimal number without a century "00" "99"
- %Y year as a decimal number including the century "2008"
- %Z time zone or name or abbreviation "UTC", "EST", "PST"
- %z same as %Z
- %% a literal "%" character "%"
-
- d Day of the month, 2 digits with leading zeros "01" to "31"
- D A textual representation of a day, three letters "Mon" through "Sun"
- j Day of the month without leading zeros "1" to "31"
- l A full textual representation of the day of the week (lowercase "L") "Sunday" through "Saturday"
- N ISO-8601 numeric representation of the day of the week (added in PHP 5.1.0) "1" (for Monday) through "7" (for Sunday)
- S English ordinal suffix for the day of the month, 2 characters "st", "nd", "rd" or "th". Works well with j
- w Numeric representation of the day of the week "0" (for Sunday) through "6" (for Saturday)
- z The day of the year (starting from "0") "0" through "365"
- W ISO-8601 week number of year, weeks starting on Monday "00" to ("52" or "53")
- F A full textual representation of a month, such as January or March "January" through "December"
- m Numeric representation of a month, with leading zeros "01" through "12"
- M A short textual representation of a month, three letters "Jan" through "Dec"
- n Numeric representation of a month, without leading zeros "1" through "12"
- t Number of days in the given month "28" through "31"
- L Whether it's a leap year "1" if it is a leap year, "0" otherwise
- o ISO-8601 year number. This has the same value as Y, except that if the "2008"
- ISO week number (W) belongs to the previous or next year, that year
- is used instead.
- Y A full numeric representation of a year, 4 digits "2008"
- y A two digit representation of a year "08"
- a Lowercase Ante meridiem and Post meridiem "am" or "pm"
- A Uppercase Ante meridiem and Post meridiem "AM" or "PM"
- B Swatch Internet time "000" through "999"
- g 12-hour format of an hour without leading zeros "1" through "12"
- G 24-hour format of an hour without leading zeros "0" through "23"
- h 12-hour format of an hour with leading zeros "01" through "12"
- H 24-hour format of an hour with leading zeros "00" through "23"
- i Minutes with leading zeros "00" to "59"
- s Seconds, with leading zeros "00" through "59"
- u Milliseconds "54321"
- e Timezone identifier "UTC", "EST", "PST"
- I Whether or not the date is in daylight saving time (uppercase i) "1" if Daylight Saving Time, "0" otherwise
- O Difference to Greenwich time (GMT) in hours "+0200", "-0600"
- P Difference to Greenwich time (GMT) with colon between hours and minutes "+02:00", "-06:00"
- T Timezone abbreviation "UTC", "EST", "PST"
- Z Timezone offset in seconds. The offset for timezones west of UTC is "-43200" through "50400"
- always negative, and for those east of UTC is always positive.
- c ISO 8601 date "2004-02-12T15:19:21+00:00"
- r RFC 2822 formatted date "Thu, 21 Dec 2000 16:01:07 +0200"
- U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) "0"
- </pre>
- * @param {String} A format string consisting of one or more format spcifiers [Optional].
- * @return {String} A string representation of the current Date object.
- */
- $P.$format = function (format) {
- var x = this,
- y,
- t = function (v) {
- $f.push(v);
- return x.toString(v);
- };
-
- return format ? format.replace(/(%|\\)?.|%%/g,
- function (m) {
- if (m.charAt(0) === "\\" || m.substring(0, 2) === "%%") {
- return m.replace("\\", "").replace("%%", "%");
- }
- switch (m) {
- case "d":
- case "%d":
- return t("dd");
- case "D":
- case "%a":
- return t("ddd");
- case "j":
- case "%e":
- return t("d");
- case "l":
- case "%A":
- return t("dddd");
- case "N":
- case "%u":
- return x.getDay() + 1;
- case "S":
- return t("S");
- case "w":
- case "%w":
- return x.getDay();
- case "z":
- return x.getOrdinalNumber();
- case "%j":
- return p(x.getOrdinalNumber(), 3);
- case "%U":
- var d1 = x.clone().set({month: 0, day: 1}).addDays(-1).moveToDayOfWeek(0),
- d2 = x.clone().addDays(1).moveToDayOfWeek(0, -1);
- return (d2 < d1) ? "00" : p((d2.getOrdinalNumber() - d1.getOrdinalNumber()) / 7 + 1);
- case "W":
- case "%V":
- return x.getISOWeek();
- case "%W":
- return p(x.getWeek());
- case "F":
- case "%B":
- return t("MMMM");
- case "m":
- case "%m":
- return t("MM");
- case "M":
- case "%b":
- case "%h":
- return t("MMM");
- case "n":
- return t("M");
- case "t":
- return $D.getDaysInMonth(x.getFullYear(), x.getMonth());
- case "L":
- return ($D.isLeapYear(x.getFullYear())) ? 1 : 0;
- case "o":
- case "%G":
- return x.setWeek(x.getISOWeek()).toString("yyyy");
- case "%g":
- return x.$format("%G").slice(-2);
- case "Y":
- case "%Y":
- return t("yyyy");
- case "y":
- case "%y":
- return t("yy");
- case "a":
- case "%p":
- return t("tt").toLowerCase();
- case "A":
- return t("tt").toUpperCase();
- case "g":
- case "%I":
- return t("h");
- case "G":
- return t("H");
- case "h":
- return t("hh");
- case "H":
- case "%H":
- return t("HH");
- case "i":
- case "%M":
- return t("mm");
- case "s":
- case "%S":
- return t("ss");
- case "u":
- return p(x.getMilliseconds(), 3);
- case "I":
- return (x.isDaylightSavingTime()) ? 1 : 0;
- case "O":
- return x.getUTCOffset();
- case "P":
- y = x.getUTCOffset();
- return y.substring(0, y.length - 2) + ":" + y.substring(y.length - 2);
- case "e":
- case "T":
- case "%z":
- case "%Z":
- return x.getTimezone();
- case "Z":
- return x.getTimezoneOffset() * -60;
- case "B":
- var now = new Date();
- return Math.floor(((now.getHours() * 3600) + (now.getMinutes() * 60) + now.getSeconds() + (now.getTimezoneOffset() + 60) * 60) / 86.4);
- case "c":
- return x.toISOString().replace(/\"/g, "");
- case "U":
- return $D.strtotime("now");
- case "%c":
- return t("d") + " " + t("t");
- case "%C":
- return Math.floor(x.getFullYear() / 100 + 1);
- case "%D":
- return t("MM/dd/yy");
- case "%n":
- return "\\n";
- case "%t":
- return "\\t";
- case "%r":
- return t("hh:mm tt");
- case "%R":
- return t("H:mm");
- case "%T":
- return t("H:mm:ss");
- case "%x":
- return t("d");
- case "%X":
- return t("t");
- default:
- $f.push(m);
- return m;
- }
- }
- ) : this._toString();
- };
-
- if (!$P.format) {
- $P.format = $P.$format;
- }
-}());
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "fa-IR",
- englishName: "Persian (Iran)",
- nativeName: "فارسى (ايران)",
-
- /* Day Name Strings */
- dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
- abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
- shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
- firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],
-
- /* Month Name Strings */
- monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
- abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
-
- /* AM/PM Designators */
- amDesignator: "ق.ظ",
- pmDesignator: "ب.ظ",
-
- firstDayOfWeek: 0,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "mdy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "M/d/yyyy",
- longDate: "dddd, MMMM dd, yyyy",
- shortTime: "hh:mm tt",
- longTime: "hh:mm:ss tt",
- fullDateTime: "dddd, MMMM dd, yyyy hh:mm:ss tt",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "MMMM dd",
- yearMonth: "MMMM, yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(uary)?/i,
- feb: /^feb(ruary)?/i,
- mar: /^mar(ch)?/i,
- apr: /^apr(il)?/i,
- may: /^may/i,
- jun: /^jun(e)?/i,
- jul: /^jul(y)?/i,
- aug: /^aug(ust)?/i,
- sep: /^sep(t(ember)?)?/i,
- oct: /^oct(ober)?/i,
- nov: /^nov(ember)?/i,
- dec: /^dec(ember)?/i,
-
- sun: /^su(n(day)?)?/i,
- mon: /^mo(n(day)?)?/i,
- tue: /^tu(e(s(day)?)?)?/i,
- wed: /^we(d(nesday)?)?/i,
- thu: /^th(u(r(s(day)?)?)?)?/i,
- fri: /^fr(i(day)?)?/i,
- sat: /^sa(t(urday)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "fi-FI",
- englishName: "Finnish (Finland)",
- nativeName: "suomi (Suomi)",
-
- /* Day Name Strings */
- dayNames: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai"],
- abbreviatedDayNames: ["su", "ma", "ti", "ke", "to", "pe", "la"],
- shortestDayNames: ["su", "ma", "ti", "ke", "to", "pe", "la"],
- firstLetterDayNames: ["s", "m", "t", "k", "t", "p", "l"],
-
- /* Month Name Strings */
- monthNames: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"],
- abbreviatedMonthNames: ["tammi", "helmi", "maalis", "huhti", "touko", "kesä", "heinä", "elo", "syys", "loka", "marras", "joulu"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "d.M.yyyy",
- longDate: "d. MMMM'ta 'yyyy",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "d. MMMM'ta 'yyyy H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "d. MMMM'ta'",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^tammi(kuu)?/i,
- feb: /^helmi(kuu)?/i,
- mar: /^maalis(kuu)?/i,
- apr: /^huhti(kuu)?/i,
- may: /^touko(kuu)?/i,
- jun: /^kesä(kuu)?/i,
- jul: /^heinä(kuu)?/i,
- aug: /^elo(kuu)?/i,
- sep: /^syys(kuu)?/i,
- oct: /^loka(kuu)?/i,
- nov: /^marras(kuu)?/i,
- dec: /^joulu(kuu)?/i,
-
- sun: /^sunnuntai/i,
- mon: /^maanantai/i,
- tue: /^tiistai/i,
- wed: /^keskiviikko/i,
- thu: /^torstai/i,
- fri: /^perjantai/i,
- sat: /^lauantai/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "fr-FR",
- englishName: "French (France)",
- nativeName: "français (France)",
-
- /* Day Name Strings */
- dayNames: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
- abbreviatedDayNames: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
- shortestDayNames: ["di", "lu", "ma", "me", "je", "ve", "sa"],
- firstLetterDayNames: ["d", "l", "m", "m", "j", "v", "s"],
-
- /* Month Name Strings */
- monthNames: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
- abbreviatedMonthNames: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc."],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd/MM/yyyy",
- longDate: "dddd d MMMM yyyy",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "dddd d MMMM yyyy HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "d MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^janv(.(ier)?)?/i,
- feb: /^févr(.(ier)?)?/i,
- mar: /^mars/i,
- apr: /^avr(.(il)?)?/i,
- may: /^mai/i,
- jun: /^juin/i,
- jul: /^juil(.(let)?)?/i,
- aug: /^août/i,
- sep: /^sept(.(embre)?)?/i,
- oct: /^oct(.(obre)?)?/i,
- nov: /^nov(.(embre)?)?/i,
- dec: /^déc(.(embre)?)?/i,
-
- sun: /^di(m(.(anche)?)?)?/i,
- mon: /^lu(n(.(di)?)?)?/i,
- tue: /^ma(r(.(di)?)?)?/i,
- wed: /^me(r(.(credi)?)?)?/i,
- thu: /^je(u(.(di)?)?)?/i,
- fri: /^ve(n(.(dredi)?)?)?/i,
- sat: /^sa(m(.(edi)?)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "gl-ES",
- englishName: "Galician (Galician)",
- nativeName: "galego (galego)",
-
- /* Day Name Strings */
- dayNames: ["domingo", "luns", "martes", "mércores", "xoves", "venres", "sábado"],
- abbreviatedDayNames: ["dom", "luns", "mar", "mér", "xov", "ven", "sab"],
- shortestDayNames: ["do", "lu", "ma", "mé", "xo", "ve", "sa"],
- firstLetterDayNames: ["d", "l", "m", "m", "x", "v", "s"],
-
- /* Month Name Strings */
- monthNames: ["xaneiro", "febreiro", "marzo", "abril", "maio", "xuño", "xullo", "agosto", "setembro", "outubro", "novembro", "decembro"],
- abbreviatedMonthNames: ["xan", "feb", "mar", "abr", "maio", "xuñ", "xull", "ago", "set", "out", "nov", "dec"],
-
- /* AM/PM Designators */
- amDesignator: "a.m.",
- pmDesignator: "p.m.",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd/MM/yy",
- longDate: "dddd, dd' de 'MMMM' de 'yyyy",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM' de 'yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^xan(eiro)?/i,
- feb: /^feb(reiro)?/i,
- mar: /^mar(zo)?/i,
- apr: /^abr(il)?/i,
- may: /^maio/i,
- jun: /^xuñ(o)?/i,
- jul: /^xull(o)?/i,
- aug: /^ago(sto)?/i,
- sep: /^set(embro)?/i,
- oct: /^out(ubro)?/i,
- nov: /^nov(embro)?/i,
- dec: /^dec(embro)?/i,
-
- sun: /^do(m(ingo)?)?/i,
- mon: /^lu(1)?/i,
- tue: /^ma(r(tes)?)?/i,
- wed: /^mé(r(cores)?)?/i,
- thu: /^xo(v(es)?)?/i,
- fri: /^ve(n(res)?)?/i,
- sat: /^sa(b(ado)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "he-IL",
- englishName: "Hebrew (Israel)",
- nativeName: "עברית (ישראל)",
-
- /* Day Name Strings */
- dayNames: ["יום ראשון", "יום שני", "יום שלישי", "יום רביעי", "יום חמישי", "יום שישי", "שבת"],
- abbreviatedDayNames: ["יום א", "יום ב", "יום ג", "יום ד", "יום ה", "יום ו", "שבת"],
- shortestDayNames: ["א", "ב", "ג", "ד", "ה", "ו", "ש"],
- firstLetterDayNames: ["א", "ב", "ג", "ד", "ה", "ו", "ש"],
-
- /* Month Name Strings */
- monthNames: ["ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"],
- abbreviatedMonthNames: ["ינו", "פבר", "מרץ", "אפר", "מאי", "יונ", "יול", "אוג", "ספט", "אוק", "נוב", "דצמ"],
-
- /* AM/PM Designators */
- amDesignator: "AM",
- pmDesignator: "PM",
-
- firstDayOfWeek: 0,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd/MM/yyyy",
- longDate: "dddd dd MMMM yyyy",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "dddd dd MMMM yyyy HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^ינו(אר)?/i,
- feb: /^פבר(ואר)?/i,
- mar: /^מרץ/i,
- apr: /^אפר(יל)?/i,
- may: /^מאי/i,
- jun: /^יונ(י)?/i,
- jul: /^יול(י)?/i,
- aug: /^אוג(וסט)?/i,
- sep: /^ספט(מבר)?/i,
- oct: /^אוק(טובר)?/i,
- nov: /^נוב(מבר)?/i,
- dec: /^דצמ(בר)?/i,
-
- sun: /^א(ום א(אשון)?)?/i,
- mon: /^ב(ום ב(ני)?)?/i,
- tue: /^ג(ום ג(לישי)?)?/i,
- wed: /^ד(ום ד(ביעי)?)?/i,
- thu: /^ה(ום ה(מישי)?)?/i,
- fri: /^ו(ום ו(ישי)?)?/i,
- sat: /^ש(1)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "hu-HU",
- englishName: "Hungarian (Hungary)",
- nativeName: "magyar (Magyarország)",
-
- /* Day Name Strings */
- dayNames: ["vasárnap", "hétfő", "kedd", "szerda", "csütörtök", "péntek", "szombat"],
- abbreviatedDayNames: ["V", "H", "K", "Sze", "Cs", "P", "Szo"],
- shortestDayNames: ["V", "H", "K", "Sze", "Cs", "P", "Szo"],
- firstLetterDayNames: ["V", "H", "K", "S", "C", "P", "S"],
-
- /* Month Name Strings */
- monthNames: ["január", "február", "március", "április", "május", "június", "július", "augusztus", "szeptember", "október", "november", "december"],
- abbreviatedMonthNames: ["jan.", "febr.", "márc.", "ápr.", "máj.", "jún.", "júl.", "aug.", "szept.", "okt.", "nov.", "dec."],
-
- /* AM/PM Designators */
- amDesignator: "de.",
- pmDesignator: "du.",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "ymd",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "yyyy. MM. dd.",
- longDate: "yyyy. MMMM d.",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "yyyy. MMMM d. H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "MMMM d.",
- yearMonth: "yyyy. MMMM"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(.(uár)?)?/i,
- feb: /^febr(.(uár)?)?/i,
- mar: /^márc(.(ius)?)?/i,
- apr: /^ápr(.(ilis)?)?/i,
- may: /^máj(.(us)?)?/i,
- jun: /^jún(.(ius)?)?/i,
- jul: /^júl(.(ius)?)?/i,
- aug: /^aug(.(usztus)?)?/i,
- sep: /^szept(.(ember)?)?/i,
- oct: /^okt(.(óber)?)?/i,
- nov: /^nov(.(ember)?)?/i,
- dec: /^dec(.(ember)?)?/i,
-
- sun: /^vasárnap/i,
- mon: /^hétfő/i,
- tue: /^kedd/i,
- wed: /^szerda/i,
- thu: /^csütörtök/i,
- fri: /^péntek/i,
- sat: /^szombat/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "id-ID",
- englishName: "Indonesian (Indonesia)",
- nativeName: "Bahasa Indonesia (Indonesia)",
-
- /* Day Name Strings */
- dayNames: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"],
- abbreviatedDayNames: ["Minggu", "Sen", "Sel", "Rabu", "Kamis", "Jumat", "Sabtu"],
- shortestDayNames: ["M", "S", "S", "R", "K", "J", "S"],
- firstLetterDayNames: ["M", "S", "S", "R", "K", "J", "S"],
-
- /* Month Name Strings */
- monthNames: ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "Nopember", "Desember"],
- abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agust", "Sep", "Okt", "Nop", "Des"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd/MM/yyyy",
- longDate: "dd MMMM yyyy",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "dd MMMM yyyy H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(uari)?/i,
- feb: /^feb(ruari)?/i,
- mar: /^mar(et)?/i,
- apr: /^apr(il)?/i,
- may: /^mei/i,
- jun: /^jun(i)?/i,
- jul: /^jul(i)?/i,
- aug: /^agust(us)?/i,
- sep: /^sep(t(ember)?)?/i,
- oct: /^okt(ober)?/i,
- nov: /^nop(ember)?/i,
- dec: /^des(ember)?/i,
-
- sun: /^m(1)?/i,
- mon: /^s(en(in)?)?/i,
- tue: /^s(el(asa)?)?/i,
- wed: /^r(1)?/i,
- thu: /^k(1)?/i,
- fri: /^j(1)?/i,
- sat: /^s(1)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "is-IS",
- englishName: "Icelandic (Iceland)",
- nativeName: "íslenska (Ísland)",
-
- /* Day Name Strings */
- dayNames: ["sunnudagur", "mánudagur", "þriðjudagur", "miðvikudagur", "fimmtudagur", "föstudagur", "laugardagur"],
- abbreviatedDayNames: ["sun.", "mán.", "þri.", "mið.", "fim.", "fös.", "lau."],
- shortestDayNames: ["su", "má", "þr", "mi", "fi", "fö", "la"],
- firstLetterDayNames: ["s", "m", "þ", "m", "f", "f", "l"],
-
- /* Month Name Strings */
- monthNames: ["janúar", "febrúar", "mars", "apríl", "maí", "júní", "júlí", "ágúst", "september", "október", "nóvember", "desember"],
- abbreviatedMonthNames: ["jan.", "feb.", "mar.", "apr.", "maí", "jún.", "júl.", "ágú.", "sep.", "okt.", "nóv.", "des."],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "d.M.yyyy",
- longDate: "d. MMMM yyyy",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "d. MMMM yyyy HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "d. MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(.(úar)?)?/i,
- feb: /^feb(.(rúar)?)?/i,
- mar: /^mar(.(s)?)?/i,
- apr: /^apr(.(íl)?)?/i,
- may: /^maí/i,
- jun: /^jún(.(í)?)?/i,
- jul: /^júl(.(í)?)?/i,
- aug: /^ágú(.(st)?)?/i,
- sep: /^sep(t(ember)?)?/i,
- oct: /^okt(.(óber)?)?/i,
- nov: /^nóv(.(ember)?)?/i,
- dec: /^des(.(ember)?)?/i,
-
- sun: /^su(n(.(nudagur)?)?)?/i,
- mon: /^má(n(.(udagur)?)?)?/i,
- tue: /^þr(i(.(ðjudagur)?)?)?/i,
- wed: /^mi(ð(.(vikudagur)?)?)?/i,
- thu: /^fi(m(.(mtudagur)?)?)?/i,
- fri: /^fö(s(.(tudagur)?)?)?/i,
- sat: /^la(u(.(gardagur)?)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "it-IT",
- englishName: "Italian (Italy)",
- nativeName: "italiano (Italia)",
-
- /* Day Name Strings */
- dayNames: ["domenica", "lunedì", "martedì", "mercoledì", "giovedì", "venerdì", "sabato"],
- abbreviatedDayNames: ["dom", "lun", "mar", "mer", "gio", "ven", "sab"],
- shortestDayNames: ["do", "lu", "ma", "me", "gi", "ve", "sa"],
- firstLetterDayNames: ["d", "l", "m", "m", "g", "v", "s"],
-
- /* Month Name Strings */
- monthNames: ["gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre"],
- abbreviatedMonthNames: ["gen", "feb", "mar", "apr", "mag", "giu", "lug", "ago", "set", "ott", "nov", "dic"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd/MM/yyyy",
- longDate: "dddd d MMMM yyyy",
- shortTime: "H.mm",
- longTime: "H.mm.ss",
- fullDateTime: "dddd d MMMM yyyy H.mm.ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^gen(naio)?/i,
- feb: /^feb(braio)?/i,
- mar: /^mar(zo)?/i,
- apr: /^apr(ile)?/i,
- may: /^mag(gio)?/i,
- jun: /^giu(gno)?/i,
- jul: /^lug(lio)?/i,
- aug: /^ago(sto)?/i,
- sep: /^set(tembre)?/i,
- oct: /^ott(obre)?/i,
- nov: /^nov(embre)?/i,
- dec: /^dic(embre)?/i,
-
- sun: /^do(m(enica)?)?/i,
- mon: /^lu(n(edì)?)?/i,
- tue: /^ma(r(tedì)?)?/i,
- wed: /^me(r(coledì)?)?/i,
- thu: /^gi(o(vedì)?)?/i,
- fri: /^ve(n(erdì)?)?/i,
- sat: /^sa(b(ato)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "ja-JP",
- englishName: "Japanese (Japan)",
- nativeName: "日本語 (日本)",
-
- /* Day Name Strings */
- dayNames: ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"],
- abbreviatedDayNames: ["日", "月", "火", "水", "木", "金", "土"],
- shortestDayNames: ["日", "月", "火", "水", "木", "金", "土"],
- firstLetterDayNames: ["日", "月", "火", "水", "木", "金", "土"],
-
- /* Month Name Strings */
- monthNames: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
- abbreviatedMonthNames: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
-
- /* AM/PM Designators */
- amDesignator: "午前",
- pmDesignator: "午後",
-
- firstDayOfWeek: 0,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "ymd",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "yyyy/MM/dd",
- longDate: "yyyy'年'M'月'd'日'",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "yyyy'年'M'月'd'日' H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "M'月'd'日'",
- yearMonth: "yyyy'年'M'月'"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^1(月)?/i,
- feb: /^2(月)?/i,
- mar: /^3(月)?/i,
- apr: /^4(月)?/i,
- may: /^5(月)?/i,
- jun: /^6(月)?/i,
- jul: /^7(月)?/i,
- aug: /^8(月)?/i,
- sep: /^9(月)?/i,
- oct: /^10(月)?/i,
- nov: /^11(月)?/i,
- dec: /^12(月)?/i,
-
- sun: /^日曜日/i,
- mon: /^月曜日/i,
- tue: /^火曜日/i,
- wed: /^水曜日/i,
- thu: /^木曜日/i,
- fri: /^金曜日/i,
- sat: /^土曜日/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "ko-KR",
- englishName: "Korean (Korea)",
- nativeName: "한국어 (대한민국)",
-
- /* Day Name Strings */
- dayNames: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"],
- abbreviatedDayNames: ["일", "월", "화", "수", "목", "금", "토"],
- shortestDayNames: ["일", "월", "화", "수", "목", "금", "토"],
- firstLetterDayNames: ["일", "월", "화", "수", "목", "금", "토"],
-
- /* Month Name Strings */
- monthNames: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"],
- abbreviatedMonthNames: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
-
- /* AM/PM Designators */
- amDesignator: "오전",
- pmDesignator: "오후",
-
- firstDayOfWeek: 0,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "ymd",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "yyyy-MM-dd",
- longDate: "yyyy'년' M'월' d'일' dddd",
- shortTime: "tt h:mm",
- longTime: "tt h:mm:ss",
- fullDateTime: "yyyy'년' M'월' d'일' dddd tt h:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "M'월' d'일'",
- yearMonth: "yyyy'년' M'월'"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^1(월)?/i,
- feb: /^2(월)?/i,
- mar: /^3(월)?/i,
- apr: /^4(월)?/i,
- may: /^5(월)?/i,
- jun: /^6(월)?/i,
- jul: /^7(월)?/i,
- aug: /^8(월)?/i,
- sep: /^9(월)?/i,
- oct: /^10(월)?/i,
- nov: /^11(월)?/i,
- dec: /^12(월)?/i,
-
- sun: /^일요일/i,
- mon: /^월요일/i,
- tue: /^화요일/i,
- wed: /^수요일/i,
- thu: /^목요일/i,
- fri: /^금요일/i,
- sat: /^토요일/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-/**
- * kronolith.js - Base application logic.
- * NOTE: ContextSensitive.js must be loaded before this file.
- *
- * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Jan Schneider <jan@horde.org>
- */
-
-/* Trick some Horde js into thinking this is the parent Horde window. */
-var frames = { horde_main: true },
-
-/* Kronolith object. */
-KronolithCore = {
- // Vars used and defaulting to null/false:
- // DMenu, Growler, inAjaxCallback, is_logout, onDoActionComplete,
- // eventForm, daySizes, viewLoading
-
- view: '',
- ecache: $H(),
- tcache: $H(),
- efifo: {},
- eventsLoading: $H(),
- loading: 0,
- date: new Date(),
- taskType: 1, //Default to all tasks view
-
- doActionOpts: {
- onException: function(r, e) { KronolitCore.debug('onException', e); },
- onFailure: function(t, o) { KronolithCore.debug('onFailure', t); },
- evalJS: false,
- evalJSON: true
- },
-
- debug: function(label, e)
- {
- if (!this.is_logout && Kronolith.conf.debug) {
- alert(label + ': ' + (e instanceof Error ? e.name + '-' + e.message : Object.inspect(e)));
- }
- },
-
- /* 'action' -> if action begins with a '*', the exact string will be used
- * instead of sending the action to the ajax handler. */
- doAction: function(action, params, callback, opts)
- {
- var b, tmp = {};
-
- opts = Object.extend(this.doActionOpts, opts || {});
- params = $H(params);
- action = action.startsWith('*')
- ? action.substring(1)
- : Kronolith.conf.URI_AJAX + '/' + action;
- if (Kronolith.conf.SESSION_ID) {
- params.update(Kronolith.conf.SESSION_ID.toQueryParams());
- }
- opts.parameters = params.toQueryString();
- opts.onComplete = function(t, o) { this.doActionComplete(t, callback); }.bind(this);
- new Ajax.Request(action, opts);
- },
-
- doActionComplete: function(request, callback)
- {
- this.inAjaxCallback = true;
-
- if (!request.responseJSON) {
- if (++this.server_error == 3) {
- this.showNotifications([ { type: 'horde.error', message: Kronolith.text.ajax_timeout } ]);
- }
- this.inAjaxCallback = false;
- return;
- }
-
- var r = request.responseJSON;
-
- if (!r.msgs) {
- r.msgs = [];
- }
-
- if (r.response && Object.isFunction(callback)) {
- try {
- callback(r);
- } catch (e) {
- this.debug('doActionComplete', e);
- }
- }
-
- if (this.server_error >= 3) {
- r.msgs.push({ type: 'horde.success', message: Kronolith.text.ajax_recover });
- }
- this.server_error = 0;
-
- if (!r.msgs_noauto) {
- this.showNotifications(r.msgs);
- }
-
- if (this.onDoActionComplete) {
- this.onDoActionComplete(r);
- }
-
- this.inAjaxCallback = false;
- },
-
- setTitle: function(title)
- {
- document.title = Kronolith.conf.name + ' :: ' + title;
- return title;
- },
-
- showNotifications: function(msgs)
- {
- if (!msgs.size() || this.is_logout) {
- return;
- }
-
- msgs.find(function(m) {
- switch (m.type) {
- case 'kronolith.timeout':
- this.logout(Kronolith.conf.timeout_url);
- return true;
-
- case 'horde.error':
- case 'horde.message':
- case 'horde.success':
- case 'horde.warning':
- this.Growler.growl(m.message, {
- className: m.type.replace('.', '-'),
- life: 8,
- log: true,
- sticky: m.type == 'horde.error'
- });
- }
- }, this);
- },
-
- logout: function(url)
- {
- this.is_logout = true;
- this.redirect(url || (Kronolith.conf.URI_IMP + '/LogOut'));
- },
-
- redirect: function(url)
- {
- url = this.addSID(url);
- if (parent.frames.horde_main) {
- parent.location = url;
- } else {
- window.location = url;
- }
- },
-
- addSID: function(url)
- {
- if (!Kronolith.conf.SESSION_ID) {
- return url;
- }
- return this.addURLParam(url, Kronolith.conf.SESSION_ID.toQueryParams());
- },
-
- addURLParam: function(url, params)
- {
- var q = url.indexOf('?');
-
- if (q != -1) {
- params = $H(url.toQueryParams()).merge(params).toObject();
- url = url.substring(0, q);
- }
- return url + '?' + Object.toQueryString(params);
- },
-
- go: function(fullloc, data)
- {
- var locParts = fullloc.split(':');
- var loc = locParts.shift();
-
- switch (loc) {
- case 'day':
- case 'week':
- case 'month':
- case 'year':
- case 'agenda':
- case 'tasks':
- var locCap = loc.capitalize();
- [ 'Day', 'Week', 'Month', 'Year', 'Tasks', 'Agenda' ].each(function(a) {
- $('kronolithNav' + a).removeClassName('on');
- });
- $('kronolithNav' + locCap).addClassName('on');
- if (this.view && this.view != loc) {
- $('kronolithView' + this.view.capitalize()).fade({ 'queue': 'end' });
- }
-
- switch (loc) {
- case 'day':
- case 'agenda':
- case 'week':
- case 'month':
- case 'year':
- var date = locParts.shift();
- if (date) {
- date = this.parseDate(date);
- } else {
- date = this.date;
- }
-
- if (this.view == loc && date.getYear() == this.date.getYear() &&
- ((loc == 'year') ||
- (loc == 'month' && date.getMonth() == this.date.getMonth()) ||
- (loc == 'week' && date.getWeek() == this.date.getWeek()) ||
- ((loc == 'day' || loc == 'agenda') && date.dateString() == this.date.dateString()))) {
- return;
- }
-
- this.updateView(date, loc);
- var dates = this.viewDates(date, loc);
- this._loadEvents(dates[0], dates[1], loc);
- if ($('kronolithView' + locCap)) {
- this.viewLoading = true;
- $('kronolithView' + locCap).appear({ 'queue': 'end', 'afterFinish': function() { this.viewLoading = false; }.bind(this) });
- }
- $('kronolithLoading' + loc).insert($('kronolithLoading').remove());
- this.updateMinical(date, loc);
- this.date = date;
-
- break;
-
- case 'tasks':
- if (this.view == loc) {
- return;
- }
- this._loadTasks(this.taskType);
- if ($('kronolithView' + locCap)) {
- this.viewLoading = true;
- $('kronolithView' + locCap).appear({ 'queue': 'end', 'afterFinish': function() { this.viewLoading = false; }.bind(this) });
- }
- $('kronolithLoading' + loc).insert($('kronolithLoading').remove());
- this.updateMinical(this.date, loc);
-
- break;
-
- default:
- if ($('kronolithView' + locCap)) {
- this.viewLoading = true;
- $('kronolithView' + locCap).appear({ 'queue': 'end', 'afterFinish': function() { this.viewLoading = false; }.bind(this) });
- }
- break;
- }
-
- this._addHistory(fullloc);
- this.view = loc;
- break;
-
- case 'search':
- [ 'Day', 'Week', 'Month', 'Year', 'Tasks', 'Agenda' ].each(function(a) {
- $('kronolithNav' + a).removeClassName('on');
- });
- if (this.view) {
- $('kronolithView' + this.view.capitalize()).fade({ 'queue': 'end' });
- }
- var cals = [], term = locParts[1],
- query = Object.toJSON({ 'title': term });
- this.updateView(null, 'search', term);
- $H(Kronolith.conf.calendars).each(function(type) {
- $H(type.value).each(function(calendar) {
- if (calendar.value.show) {
- cals.push(type.key + '|' + calendar.key);
- }
- });
- });
- this.startLoading('search', query, '');
- this.doAction('Search' + locParts[0],
- { 'cals': cals.toJSON(), 'query': query },
- function(r) {
- // Hide spinner.
- this.loading--;
- if (!this.loading) {
- $('kronolithLoading').hide();
- }
- if (r.response.view != 'search' ||
- r.response.query != this.eventsLoading['search'] ||
- Object.isUndefined(r.response.events)) {
- return;
- }
- $H(r.response.events).each(function(calendars) {
- $H(calendars.value).each(function(events) {
- this.createAgendaDay(events.key);
- $H(events.value).each(function(event) {
- event.value.calendar = calendars.key;
- event.value.start = Date.parse(event.value.s);
- event.value.end = Date.parse(event.value.e);
- this._insertEvent(event, events.key, 'agenda');
- }, this);
- }, this);
- }, this);
- }.bind(this));
- this.viewLoading = true;
- $('kronolithViewAgenda').appear({ 'queue': 'end', 'afterFinish': function() { this.viewLoading = false; }.bind(this) });
- $('kronolithLoadingagenda').insert($('kronolithLoading').remove());
- this.updateMinical(this.date, 'search');
- this._addHistory(fullloc);
- this.view = 'agenda';
- break;
-
- case 'event':
- if (!this.view) {
- this.go(Kronolith.conf.login_view);
- this.go.bind(this, fullloc, data).defer();
- return;
- }
- switch (locParts.length) {
- case 0:
- this.editEvent();
- break;
- case 1:
- this.editEvent(null, null, locParts[0]);
- break;
- case 2:
- this.editEvent(locParts[0], locParts[1]);
- break;
- }
- this.updateMinical(this.date, this.view);
- this._addHistory(fullloc);
- break;
-
- case 'options':
- //this.highlightSidebar('appoptions');
- this._addHistory(loc);
- this.setTitle(Kronolith.text.prefs);
- this.iframeContent(loc, Kronolith.conf.prefs_url);
- break;
- }
- },
-
- /**
- * Rebuilds one of the calendar views for a new date.
- *
- * @param Date date The date to show in the calendar.
- * @param string view The view that's rebuilt.
- * @param mixed data Any additional data that might be required.
- */
- updateView: function(date, view, data)
- {
- switch (view) {
- case 'day':
- this.dayEvents = [];
- this.dayGroups = [];
- this.allDayEvents = [];
- $('kronolithViewDay').down('caption span').innerHTML = this.setTitle(date.toString('D'));
- break;
-
- case 'week':
- this.dayEvents = [];
- this.dayGroups = [];
- this.allDayEvents = [];
- var div = $('kronolithEventsWeek').down('div'),
- th = $('kronolithViewWeekHead').down('.kronolithWeekDay'),
- td = $('kronolithViewWeekBody').down('td').next('td'),
- dates = this.viewDates(date, view),
- day = dates[0].clone();
-
- $('kronolithViewWeek').down('caption span').innerHTML = this.setTitle(Kronolith.text.week.interpolate({ 'week': date.getWeek() }));
-
- for (var i = 0; i < 7; i++) {
- div.writeAttribute('id', 'kronolithEventsWeek' + day.dateString());
- th.writeAttribute('date', day.dateString()).down('span').innerHTML = day.toString('dddd, d');
- td.down('div').writeAttribute('id', 'kronolithAllDay' + day.dateString());
- div = div.next('div');
- th = th.next('td');
- td = td.next('td');
- day.next().day();
- }
- break;
-
- case 'month':
- var tbody = $('kronolithViewMonthBody'),
- dates = this.viewDates(date, view),
- day = dates[0].clone(), row;
-
- $('kronolithViewMonth').down('caption span').innerHTML = this.setTitle(date.toString('MMMM yyyy'));
-
- // Remove old rows. Maybe we should only rebuild the calendars if
- // necessary.
- tbody.childElements().each(function(row) {
- if (row.identify() != 'kronolithRowTemplate') {
- row.remove();
- }
- });
-
- // Build new calendar view.
- while (!day.isAfter(dates[1])) {
- tbody.insert(this.createWeekRow(day, date.getMonth(), dates).show());
- day.next().week();
- }
- this._equalRowHeights(tbody);
-
- break;
-
- case 'year':
- var viewBody = $('kronolithViewYear'), month;
-
- viewBody.down('caption span').innerHTML = this.setTitle(date.toString('yyyy'));
-
- // Build new calendar view.
- for (month = 0; month < 12; month++) {
- $('kronolithYear' + month).update(this.createYearMonth(date.getFullYear(), month).show());
- }
-
- break;
-
- case 'agenda':
- case 'search':
- // Agenda days are only created on demand, if there are any events
- // to add.
- if (view == 'agenda') {
- var dates = this.viewDates(date, view),
- day = dates[0].clone();
- $('kronolithViewAgenda').down('caption span').innerHTML = this.setTitle(Kronolith.text.agenda + ' ' + dates[0].toString('d') + ' - ' + dates[1].toString('d'));
- } else {
- $('kronolithViewAgenda').down('caption span').update(this.setTitle(Kronolith.text.searching.interpolate({ 'term': data })));
- }
-
- // Remove old rows. Maybe we should only rebuild the calendars if
- // necessary.
- tbody = $('kronolithViewAgendaBody').childElements().each(function(row) {
- if (row.identify() != 'kronolithAgendaTemplate') {
- row.remove();
- }
- });
-
- break;
- }
- },
-
- /**
- * Creates a single row of day cells for usage in the month and multi-week
- * views.
- *
- * @param Date date The first day to show in the row.
- * @param integer month The current month. Days not from the current
- * month get the kronolithOtherMonth CSS class
- * assigned.
- * @param array viewDates Array of Date objects with the start and end
- * dates of the view.
- *
- * @return Element The element rendering a week row.
- */
- createWeekRow: function(date, month, viewDates)
- {
- var monday = date.clone(), day = date.clone(),
- today = new Date().dateString(),
- start = viewDates[0].dateString(), end = viewDates[1].dateString(),
- row, cell, dateString;
-
- // Find monday of the week, to determine the week number.
- if (monday.getDay() != 1) {
- monday.moveToDayOfWeek(1, 1);
- }
-
- // Create a copy of the row template.
- row = $('kronolithRowTemplate').cloneNode(true);
- row.removeAttribute('id');
-
- // Fill week number and day cells.
- cell = row.down()
- .setText(monday.getWeek())
- .writeAttribute('date', monday.dateString())
- .next();
- while (cell) {
- dateString = day.dateString();
- cell.id = 'kronolithMonthDay' + dateString;
- cell.writeAttribute('date', dateString);
- cell.removeClassName('kronolithOtherMonth').removeClassName('kronolithToday');
- if (day.getMonth() != month) {
- cell.addClassName('kronolithOtherMonth');
- }
- if (dateString == today) {
- cell.addClassName('kronolithToday');
- }
- new Drop(cell, { onDrop: function(drop) {
- var el = DragDrop.Drags.drag.element,
- eventid = el.readAttribute('eventid'),
- cal = el.readAttribute('calendar');
- if (drop == el.parentNode) {
- return;
- }
- drop.insert(el);
- this.startLoading(cal, start, end);
- this.doAction('UpdateEvent',
- { 'cal': cal,
- 'id': eventid,
- 'view': this.view,
- 'view_start': start,
- 'view_end': end,
- 'att': $H({ start_date: drop.readAttribute('date') }).toJSON() },
- function(r) {
- if (r.response.events) {
- this._removeEvent(eventid, cal);
- }
- this._loadEventsCallback(r);
- }.bind(this));
- }.bind(this) });
- cell.down('.kronolithDay')
- .writeAttribute('date', dateString)
- .innerHTML = day.getDate();
- cell.down('.kronolithAddEvent')
- .writeAttribute('date', dateString);
- cell = cell.next();
- day.add(1).day();
- }
-
- return row;
- },
-
- /**
- * Creates a table row for a single day in the agenda view, if it doesn't
- * exist yet.
- *
- * @param string date The day to show in the row.
- *
- * @return Element The element rendering a week row.
- */
- createAgendaDay: function(date)
- {
- // Exit if row exists already.
- if ($('kronolithAgendaDay' + date)) {
- return;
- }
-
- // Create a copy of the row template.
- var body = $('kronolithViewAgendaBody'),
- row = $('kronolithAgendaTemplate').cloneNode(true);
- row.removeAttribute('id');
-
- // Fill week number and day cells.
- row.addClassName('kronolithRow' + (body.select('tr').length % 2 == 1 ? 'Odd' : 'Even'))
- .down()
- .setText(this.parseDate(date).toString('D'))
- .writeAttribute('date', date)
- .next()
- .writeAttribute('id', 'kronolithAgendaDay' + date);
-
- // Insert row.
- var nextRow;
- body.childElements().each(function(elm) {
- if (elm.down().readAttribute('date') > date) {
- nextRow = elm;
- return;
- }
- });
- if (nextRow) {
- nextRow.insert({ 'before': row.show() });
- } else {
- body.insert(row.show());
- }
-
- return row;
- },
-
- /**
- * Creates a table for a single month in the year view.
- *
- * @param integer year The year.
- * @param integer month The month.
- *
- * @return Element The element rendering a month table.
- */
- createYearMonth: function(year, month)
- {
- // Create a copy of the month template.
- var table = $('kronolithYearTemplate').cloneNode(true),
- tbody = table.down('tbody');
- table.removeAttribute('id');
- tbody.writeAttribute('id', 'kronolithYearTable' + month)
-
- // Set month name.
- table.down('SPAN')
- .writeAttribute('date', year.toPaddedString(4) + (month + 1).toPaddedString(2) + '01')
- .innerHTML = Date.CultureInfo.monthNames[month];
-
- // Build month table.
- this.buildMinical(tbody, new Date(year, month, 1));
-
- return table;
- },
-
- _equalRowHeights: function(tbody)
- {
- var children = tbody.childElements();
- children.invoke('setStyle', { 'height': (100 / (children.size() - 1)) + '%' });
- },
-
- /**
- * Calculates some dimensions for the day and week view.
- *
- * @param string storage Property name where the dimensions are stored.
- * @param string view DOM node ID of the view.
- */
- _calculateRowSizes: function(storage, view)
- {
- if (!Object.isUndefined(this[storage])) {
- return;
- }
-
- this[storage] = {};
- var trA = $(view).down('.kronolithAllDay'),
- tdA = trA.down('td'),
- tr = trA.next('tr'),
- td = tr.down('td'), height;
- this[storage].offset = tr.offsetTop - trA.offsetTop;
- this[storage].height = tr.next('tr').offsetTop - tr.offsetTop;
- this[storage].spacing = this[storage].height - tr.getHeight()
- + parseInt(td.getStyle('borderTopWidth'))
- + parseInt(td.getStyle('borderBottomWidth'));
- this[storage].allDay = tr.offsetTop - trA.offsetTop;
- this[storage].allDay -= this[storage].allDay - trA.getHeight()
- + parseInt(td.getStyle('borderTopWidth'))
- + parseInt(tdA.getStyle('borderBottomWidth'));
- },
-
- /**
- * Rebuilds the mini calendar.
- *
- * @param Date date The date to show in the calendar.
- * @param string view The view that's displayed, determines which days in
- * the mini calendar are highlighted.
- */
- updateMinical: function(date, view)
- {
- // Update header.
- $('kronolithMinicalDate').writeAttribute('date', date.dateString()).innerHTML = date.toString('MMMM yyyy');
-
- this.buildMinical($('kronolithMinical').down('tbody'), date, view);
-
- $('kronolithMenuCalendars').setStyle({ 'bottom': $('kronolithMenuBottom').getHeight() + 'px' });
- },
-
- /**
- * Creates a mini calendar suitable for the navigation calendar and the
- * year view.
- *
- * @param Element tbody The table body to add the days to.
- * @param Date date The date to show in the calendar.
- * @param string view The view that's displayed, determines which days in
- * the mini calendar are highlighted.
- */
- buildMinical: function(tbody, date, view)
- {
- var dates = this.viewDates(date, 'month'), day = dates[0].clone(),
- date7 = date.clone().add(1).week(),
- weekStart, weekEnd, weekEndDay, td, tr;
-
- // Remove old calendar rows. Maybe we should only rebuild the minical
- // if necessary.
- tbody.childElements().invoke('remove');
-
- while (day.compareTo(dates[1]) < 1) {
- // Create calendar row and insert week number.
- if (day.getDay() == Kronolith.conf.week_start) {
- tr = new Element('tr');
- tbody.insert(tr);
- td = new Element('td', { 'class': 'kronolithMinicalWeek', 'weekdate': day.dateString() }).innerHTML = day.getWeek();
- tr.insert(td);
- weekStart = day.clone();
- weekEnd = day.clone();
- weekEnd.add(6).days();
- }
- // Insert day cell.
- td = new Element('td', {date: day.dateString()});
- if (day.getMonth() != date.getMonth()) {
- td.addClassName('kronolithMinicalEmpty');
- }
- // Highlight days currently being displayed.
- if (view &&
- (view == 'month' ||
- (view == 'week' && date.between(weekStart, weekEnd)) ||
- (view == 'day' && date.equals(day)) ||
- (view == 'agenda' && !day.isBefore(date) && day.isBefore(date7)))) {
- td.addClassName('kronolithSelected');
- }
- td.innerHTML = day.getDate();
- tr.insert(td);
- day.next().day();
- }
- },
-
- /**
- * Rebuilds the list of calendars.
- */
- updateCalendarList: function()
- {
- var my = 0, shared = 0, ext = {}, extNames = {},
- remote, api, div;
-
- $H(Kronolith.conf.calendars.internal).each(function(cal) {
- if (cal.value.owner) {
- my++;
- div = $('kronolithMyCalendars');
- } else {
- shared++;
- div = $('kronolithSharedCalendars');
- }
- div.insert(new Element('DIV', { 'calendar': cal.key, 'calendarclass': 'internal', 'class': cal.value.show ? 'kronolithCalOn' : 'kronolithCalOff' })
- .setStyle({ backgroundColor: cal.value.bg, color: cal.value.fg })
- .update(cal.value.name));
- });
- if (my) {
- $('kronolithMyCalendars').show();
- } else {
- $('kronolithMyCalendars').hide();
- }
- if (shared) {
- $('kronolithSharedCalendars').show();
- } else {
- $('kronolithSharedCalendars').hide();
- }
-
- $H(Kronolith.conf.calendars.external).each(function(cal) {
- api = cal.key.split('/');
- if (typeof ext[api[0]] == 'undefined') {
- ext[api[0]] = {};
- }
- ext[api[0]][api[1]] = cal.value;
- extNames[api[0]] = cal.value.api;
- });
- $H(ext).each(function(api) {
- $('kronolithExternalCalendars')
- .insert(new Element('H3')
- .insert(new Element('A', { 'class': 'kronolithAdd' })
- .update('+'))
- .insert({ bottom: extNames[api.key] }))
- .insert(new Element('DIV', { 'id': 'kronolithExternalCalendar' + api.key, 'class': 'kronolithCalendars' }));
- $H(api.value).each(function(cal) {
- $('kronolithExternalCalendar' + api.key)
- .insert(new Element('DIV', { 'calendar': api.key + '/' + cal.key, 'calendarclass': 'external', 'class': cal.value.show ? 'kronolithCalOn' : 'kronolithCalOff' })
- .setStyle({ backgroundColor: cal.value.bg, color: cal.value.fg })
- .update(cal.value.name));
- });
- });
-
- remote = $H(Kronolith.conf.calendars.remote);
- remote.each(function(cal) {
- $('kronolithRemoteCalendars')
- .insert(new Element('DIV', { 'calendar': cal.key, 'calendarclass': 'remote', 'class': cal.value.show ? 'kronolithCalOn' : 'kronolithCalOff' })
- .setStyle({ backgroundColor: cal.value.bg, color: cal.value.fg })
- .update(cal.value.name));
- });
- if (remote.size()) {
- $('kronolithRemoteCalendars').show();
- } else {
- $('kronolithRemoteCalendars').hide();
- }
- },
-
- /**
- * Sets the load signature and show the loading spinner.
- *
- * @param string cal The loading calendar.
- * @param string start The first day of the loading view.
- * @param string end The last day of the loading view.
- */
- startLoading: function(cal, start, end)
- {
- this.eventsLoading[cal] = start + end;
- this.loading++;
- $('kronolithLoading').show();
- },
-
- /**
- */
- _loadEvents: function(firstDay, lastDay, view, calendars)
- {
- if (typeof calendars == 'undefined') {
- calendars = [];
- $H(Kronolith.conf.calendars).each(function(type) {
- $H(type.value).each(function(cal) {
- if (cal.value.show) {
- calendars.push([type.key, cal.key]);
- }
- });
- });
- }
-
- calendars.each(function(cal) {
- var startDay = firstDay.clone(), endDay = lastDay.clone(),
- cals = this.ecache.get(cal[0]),
- events, date;
-
- if (typeof cals != 'undefined' &&
- typeof cals.get(cal[1]) != 'undefined') {
- cals = cals.get(cal[1]);
- while (!Object.isUndefined(cals.get(startDay.dateString())) &&
- startDay.isBefore(endDay)) {
- this._insertEvents([startDay, startDay], view, cal.join('|'));
- startDay.add(1).day();
- }
- while (!Object.isUndefined(cals.get(endDay.dateString())) &&
- (!startDay.isAfter(endDay))) {
- this._insertEvents([endDay, endDay], view, cal.join('|'));
- endDay.add(-1).day();
- }
- if (startDay.compareTo(endDay) > 0) {
- return;
- }
- }
- var start = startDay.dateString(), end = endDay.dateString(),
- calendar = cal.join('|');
- this.startLoading(calendar, start, end);
- this._storeCache($H(), calendar);
- this.doAction('ListEvents', { start: start, end: end, cal: calendar, view: view }, this._loadEventsCallback.bind(this));
- }, this);
- },
-
- /**
- * Callback method for inserting events in the current view.
- *
- * @param object r The ajax response object.
- */
- _loadEventsCallback: function(r)
- {
- // Hide spinner.
- this.loading--;
- if (!this.loading) {
- $('kronolithLoading').hide();
- }
-
- var start = this.parseDate(r.response.sig.substr(0, 8)),
- end = this.parseDate(r.response.sig.substr(8, 8)),
- dates = [start, end];
-
- this._storeCache(r.response.events || {}, r.response.cal, dates);
-
- // Check if this is the still the result of the most current request.
- if (r.response.view != this.view ||
- r.response.sig != this.eventsLoading[r.response.cal]) {
- return;
- }
-
- this._insertEvents(dates, this.view, r.response.cal);
- },
-
- /**
- * Reads events from the cache and inserts them into the view.
- *
- * If inserting events into day and week views, the calendar parameter is
- * ignored, and events from all visible calendars are inserted instead.
- * This is necessary because the complete view has to be re-rendered if
- * events are not in chronological order.
- * The year view is specially handled too because there are no individual
- * events, only a summary of all events per day.
- *
- * @param Array dates Start and end of dates to process.
- * @param string view The view to update.
- * @param string calendar The calendar to update.
- */
- _insertEvents: function(dates, view, calendar)
- {
- switch (view) {
- case 'day':
- case 'week':
- // The day and week views require the view to be completely
- // loaded, to correctly calculate the dimensions.
- if (this.viewLoading || this.view != view) {
- this._insertEvents.bind(this, [dates[0].clone(), dates[1].clone()], view, calendar).defer();
- return;
- }
- break;
- }
-
- var day = dates[0].clone(), date;
- while (!day.isAfter(dates[1])) {
- date = day.dateString();
- switch (view) {
- case 'day':
- case 'week':
- this.dayEvents = [];
- this.dayGroups = [];
- this.allDayEvents = [];
- if (view == 'day') {
- $$('.kronolithEvent').invoke('remove');
- } else {
- $('kronolithEventsWeek' + date)
- .select('.kronolithEvent')
- .invoke('remove');
- $('kronolithAllDay' + date)
- .select('.kronolithEvent')
- .invoke('remove');
- }
- break;
-
- case 'month':
- $('kronolithMonthDay' + date)
- .select('div[calendar=' + calendar + ']')
- .invoke('remove');
- break;
-
- case 'year':
- title = '';
- busy = false;
- }
-
- this._getCacheForDate(date).sortBy(this._sortEvents).each(function(event) {
- switch (view) {
- case 'month':
- case 'agenda':
- if (calendar != event.value.calendar) {
- return;
- }
- break;
-
- case 'year':
- if (event.value.al) {
- title += Kronolith.text.allday;
- } else {
- title += event.value.start.toString('t') + '-' + event.value.end.toString('t');
- }
- title += ': ' + event.value.t;
- if (event.value.x == Kronolith.conf.status.tentative ||
- event.value.x == Kronolith.conf.status.confirmed) {
- busy = true;
- }
- title += '<br />';
- return;
- }
- this._insertEvent(event, date, view);
- }, this);
-
- if (view == 'year') {
- td = $('kronolithYearTable' + day.getMonth()).down('td[date=' + date + ']');
- td.className = '';
- if (title) {
- td.writeAttribute('title', title).addClassName('kronolithHasEvents');
- if (td.readAttribute('nicetitle')) {
- Horde_ToolTips.detach(td);
- }
- Horde_ToolTips.attach(td);
- if (busy) {
- td.addClassName('kronolithIsBusy');
- }
- }
- }
-
- day.next().day();
- }
- // Workaround Firebug bug.
- Prototype.emptyFunction();
- },
-
- /**
- * Creates the DOM node for an event bubble and inserts it into the view.
- *
- * @param object event A Hash member with the event to insert.
- * @param string date The day to update.
- * @param string view The view to update.
- */
- _insertEvent: function(event, date, view)
- {
- event.value.nodeId = 'kronolithEvent' + view + event.value.calendar + date + event.key;
-
- _createElement = function(event) {
- return new Element('DIV', {
- 'id': event.value.nodeId,
- 'calendar': event.value.calendar,
- 'eventid' : event.key,
- 'class': 'kronolithEvent'
- });
- };
-
- switch (view) {
- case 'day':
- case 'week':
- var storage = view + 'Sizes',
- div = _createElement(event),
- style = { 'backgroundColor': event.value.bg,
- 'color': event.value.fg };
-
- this._calculateRowSizes(storage, view == 'day' ? 'kronolithViewDay' : 'kronolithViewWeek');
-
- if (event.value.al) {
- if (view == 'day') {
- $('kronolithViewDayBody').down('td').next('td').insert(div.setStyle(style));
- } else {
- $('kronolithAllDay' + date).insert(div.setStyle(style));
- }
- break;
- }
-
- var midnight = this.parseDate(date),
- innerDiv = new Element('DIV', { 'class': 'kronolithEventInfo' }),
- draggerTop = new Element('DIV', { 'id': event.value.nodeId + 'top', 'class': 'kronolithDragger kronolithDraggerTop' }).setStyle(style),
- draggerBottom = new Element('DIV', { 'id': event.value.nodeId + 'bottom', 'class': 'kronolithDragger kronolithDraggerBottom' }).setStyle(style);
-
- div.setStyle({
- 'top': ((midnight.getElapsed(event.value.start) / 60000 | 0) * this[storage].height / 60 + this[storage].offset | 0) + 'px',
- 'height': ((event.value.start.getElapsed(event.value.end) / 60000 | 0) * this[storage].height / 60 - this[storage].spacing | 0) + 'px',
- 'width': '100%'
- })
- .insert(innerDiv.setStyle(style))
- .insert(draggerTop)
- .insert(draggerBottom);
- $(view == 'day' ? 'kronolithEventsDay' : 'kronolithEventsWeek' + date).insert(div);
-
- if (event.value.pe) {
- div.addClassName('kronolithEditable').setStyle({ 'cursor': 'move' });
- var minTop = this[storage].allDay + this[storage].spacing,
- step = this[storage].height / 6,
- dragTop = draggerTop.cumulativeOffset()[1],
- dragBottom = draggerBottom.cumulativeOffset()[1],
- dragBottomHeight = draggerBottom.getHeight(),
- eventTop = div.cumulativeOffset()[1],
- maxTop = div.offsetTop + draggerBottom.offsetTop
- - this[storage].allDay - this[storage].spacing
- - draggerTop.getHeight()
- - parseInt(innerDiv.getStyle('lineHeight')),
- minBottom = div.offsetTop
- - this[storage].allDay - this[storage].spacing
- + draggerTop.getHeight() - dragBottomHeight
- + parseInt(innerDiv.getStyle('lineHeight')),
- maxBottom = 24 * KronolithCore[storage].height
- + this[storage].allDay
- - dragBottomHeight - minTop,
- divHeight = div.getHeight(),
- maxDiv = 24 * KronolithCore[storage].height
- + this[storage].allDay
- - divHeight - minTop,
- opts = {
- 'threshold': 5,
- 'constraint': 'vertical',
- 'scroll': 'kronolithBody',
- 'nodrop': true,
- 'parentElement': function() {
- return $(view == 'day' ? 'kronolithEventsDay' : 'kronolithEventsWeek' + date);
- },
- 'onStart': function(d, e) {
- this.addClassName('kronolithSelected');
- }.bind(div),
- 'onEnd': function(d, e) {
- this[0]._onDragEnd(d, this[1], innerDiv, event, midnight, view);
- }.bind([this, div]),
- 'onDrag': function(d, e) {
- var top = d.ghost.cumulativeOffset()[1],
- draggingTop = d.ghost.hasClassName('kronolithDraggerTop'),
- offset, height, dates;
- if (draggingTop) {
- offset = top - dragTop;
- height = this[1].offsetHeight - offset;
- this[1].setStyle({
- 'top': (this[1].offsetTop + offset) + 'px',
- });
- offset = d.ghost.offsetTop - minTop;
- dragTop = top;
- } else {
- offset = top - dragBottom;
- height = this[1].offsetHeight + offset;
- offset = this[1].offsetTop - this[0][storage].allDay - this[0][storage].spacing;
- dragBottom = top;
- }
- this[1].setStyle({
- 'height': height + 'px'
- });
- this[0]._calculateEventDates(event.value, storage, step, offset, height);
- innerDiv.update('(' + event.value.start.toString(Kronolith.conf.time_format) + ' - ' + event.value.end.toString(Kronolith.conf.time_format) + ') ' + event.value.t);
- }.bind([this, div])
- };
-
- opts.snap = function(x, y, elm) {
- y = Math.max(0, step * (Math.min(maxTop, y - minTop) / step | 0)) + minTop;
- return [0, y];
- }
- new Drag(event.value.nodeId + 'top', opts);
-
- opts.snap = function(x, y, elm) {
- y = Math.min(maxBottom, step * (Math.max(minBottom, y - minTop - dragBottomHeight) / step | 0) + dragBottomHeight) + minTop;
- return [0, y];
- }
- new Drag(event.value.nodeId + 'bottom', opts);
-
- if (view == 'week') {
- var dates = this.viewDates(midnight, view),
- eventStart = event.value.start.clone(),
- eventEnd = event.value.end.clone(),
- minLeft = $('kronolithEventsWeek' + dates[0].toString('yyyyMMdd')).offsetLeft - $('kronolithEventsWeek' + date).offsetLeft,
- maxLeft = $('kronolithEventsWeek' + dates[1].toString('yyyyMMdd')).offsetLeft - $('kronolithEventsWeek' + date).offsetLeft,
- stepX = (maxLeft - minLeft) / 6;
- }
- new Drag(div, {
- 'threshold': 5,
- 'nodrop': true,
- 'parentElement': function() { return $(view == 'day' ? 'kronolithEventsDay' : 'kronolithEventsWeek' + date); },
- 'snap': function(x, y, elm) {
- if (view == 'week') {
- x = Math.max(minLeft, stepX * ((Math.min(maxLeft, x) + stepX / 2) / stepX | 0));
- } else {
- x = 0;
- }
- y = Math.max(0, step * (Math.min(maxDiv, y - minTop) / step | 0)) + minTop;
- return [x, y];
- },
- 'onStart': function(d, e) {
- this.addClassName('kronolithSelected');
- this.setStyle({ 'left': 0, 'width': '100%', 'zIndex': 1 });
- }.bind(div),
- 'onDrag': function(d, e) {
- if (Object.isUndefined(d.innerDiv)) {
- d.innerDiv = d.ghost.select('.kronolithEventInfo')[0];
- }
- if (view == 'week') {
- var offsetX = Math.round(d.ghost.offsetLeft / stepX);
- this[0]._calculateEventDates(event.value, storage, step, d.ghost.offsetTop - minTop, divHeight, eventStart.clone().addDays(offsetX), eventEnd.clone().addDays(offsetX));
- } else {
- this[0]._calculateEventDates(event.value, storage, step, d.ghost.offsetTop - minTop, divHeight);
- }
- d.innerDiv.update('(' + event.value.start.toString(Kronolith.conf.time_format) + ' - ' + event.value.end.toString(Kronolith.conf.time_format) + ') ' + event.value.t);
- this[1].clonePosition(d.ghost);
- }.bind([this, div]),
- 'onEnd': function(d, e) {
- this[0]._onDragEnd(d, this[1], innerDiv, event, midnight, view);
- }.bind([this, div]),
- });
- }
-
- var column = 1, columns, width, left, conflict = false,
- pos = this.dayGroups.length, placeFound = false;
-
- this.dayEvents.each(function(ev) {
- if (!ev.end.isAfter(event.value.start)) {
- placeFound = ev;
- return;
- }
-
- if (!conflict) {
- conflict = ev;
- for (i = 0; i < this.dayGroups.length; i++) {
- if (this.dayGroups[i].indexOf(conflict) != -1) {
- if (this.dayGroups[i].indexOf(placeFound) == -1) {
- placeFound = false;
- }
- break;
- }
- }
- }
- if (!placeFound) {
- column++;
- }
- }, this);
- event.value.column = column;
-
- if (conflict) {
- for (i = 0; i < this.dayGroups.length; i++) {
- if (this.dayGroups[i].indexOf(conflict) != -1) {
- pos = i;
- break;
- }
- }
- columns = Math.max(conflict.columns, column);
- } else {
- columns = column;
- }
- if (Object.isUndefined(this.dayGroups[pos])) {
- this.dayGroups[pos] = [];
- }
- this.dayGroups[pos].push(event.value);
- width = 100 / columns;
- this.dayGroups[pos].each(function(ev) {
- ev.columns = columns;
- $(ev.nodeId).setStyle({ 'width': width + '%', 'left': (width * (ev.column - 1)) + '%' });
- });
- this.dayEvents.push(event.value);
-
- div = innerDiv;
- break;
-
- case 'month':
- var div = _createElement(event)
- .setStyle({ 'backgroundColor': event.value.bg,
- 'color': event.value.fg });
-
- $('kronolithMonthDay' + date).insert(div);
- if (event.value.pe) {
- div.setStyle({ 'cursor': 'move' });
- new Drag('kronolithEventmonth' + event.value.calendar + date + event.key, { threshold: 5, parentElement: function() { return $('kronolithViewMonthBody'); }, snapToParent: true });
- }
- break;
-
- case 'agenda':
- var div = _createElement(event)
- .setStyle({ 'backgroundColor': event.value.bg,
- 'color': event.value.fg });
- if (!event.value.al) {
- div.update(new Element('SPAN', { 'class': 'kronolithDate' }).update(event.value.start.toString('t')))
- .insert(' ')
- .insert(new Element('SPAN', { 'class': 'kronolithSep' }).update('·'))
- .insert(' ');
- }
- this.createAgendaDay(date);
- $('kronolithAgendaDay' + date).insert(div);
- break;
- }
-
- this._setEventText(div, event.value)
- .observe('mouseover', div.addClassName.curry('kronolithSelected'))
- .observe('mouseout', div.removeClassName.curry('kronolithSelected'));
- },
-
- _setEventText: function(div, event)
- {
- if (event.ic) {
- div.insert(new Element('IMG', { 'src': event.ic }));
- }
- div.insert(event.t);
- if (event.a) {
- div.insert(' ')
- .insert(new Element('IMG', { 'src': Kronolith.conf.URI_IMG + 'alarm-' + event.fg.substr(1) + '.png', 'title': Kronolith.text.alarm + ' ' + event.a }));
- }
- if (event.r) {
- div.insert(' ')
- .insert(new Element('IMG', { 'src': Kronolith.conf.URI_IMG + 'recur-' + event.fg.substr(1) + '.png', 'title': Kronolith.text.recur[event.r] }));
- }
- return div;
- },
-
- _removeEvent: function(event, calendar)
- {
- this._deleteCache(event, calendar);
- $('kronolithBody').select('div[calendar=' + calendar + '][eventid=' + event + ']').invoke('remove');
- },
-
- /**
- * Calculates the event's start and end dates based on some drag and drop
- * information.
- */
- _calculateEventDates: function(event, storage, step, offset, height, start, end)
- {
- if (!Object.isUndefined(start)) {
- event.start = start;
- event.end = end;
- }
- event.start.set({
- hour: offset / this[storage].height | 0,
- minute: Math.round(offset % this[storage].height / step * 10)
- });
- event.end.set({
- hour: (offset + height + this[storage].spacing) / this[storage].height | 0,
- minute: Math.round((offset + height + this[storage].spacing) % this[storage].height / step * 10)
- });
- },
-
- /**
- * Called as the event handler after dragging/resizing a day/week event.
- */
- _onDragEnd: function(drag, div, innerDiv, event, date, view)
- {
- var dates = this.viewDates(date, view),
- start = dates[0].toString('yyyyMMdd'),
- end = dates[1].toString('yyyyMMdd');
- div.removeClassName('kronolithSelected');
- this._setEventText(innerDiv, event.value);
- drag.destroy();
- this.startLoading(event.value.calendar, start, end);
- this.doAction(
- 'UpdateEvent',
- { 'cal': event.value.calendar,
- 'id': event.key,
- 'view': view,
- 'view_start': start,
- 'view_end': end,
- 'att': $H({
- start: event.value.start,
- end: event.value.end,
- }).toJSON()
- },
- function(r) {
- if (r.response.events) {
- this._removeEvent(event.key, event.value.calendar);
- }
- this._loadEventsCallback(r);
- }.bind(this));
- },
-
- /**
- * Loads tasks, either from cache or from the server.
- *
- * @param integer taskType The tasks type, (1 = all tasks,
- * 0 = incomplete tasks, 2 = complete tasks,
- * 3 = future tasks, 4 = future and incomplete
- * tasks)
- * @param Array tasksLists The lists from where to obtain the tasks
- */
- _loadTasks: function(taskType, taskLists)
- {
- if (Object.isUndefined(taskLists)) {
- taskLists = [];
- // FIXME: Temporary hack to get the tasklists
- $H(Kronolith.conf.calendars.external).each(function(cal) {
- if (cal.value.api = 'Tasks' && cal.value.show)
- {
- taskLists.push(cal.key.substring(6));
- }
- });
- }
-
- taskLists.each(function(taskList) {
- var list = this.tcache.get(taskList);
- if (!Object.isUndefined(list)) {
- this._insertTasks(taskType, taskList);
- return;
- }
-
- this.startLoading('tasks:' + taskList, taskType, '');
- this._storeTasksCache($H(), taskList);
- this.doAction('ListTasks', { 'taskType': taskType, 'list': taskList }, this._loadTasksCallback.bind(this));
- }, this);
- },
-
- /**
- * Callback method for inserting tasks in the current view.
- *
- * @param object r The ajax response object.
- */
- _loadTasksCallback: function(r)
- {
- // Hide spinner.
- this.loading--;
- if (!this.loading) {
- $('kronolithLoading').hide();
- }
-
- this._storeTasksCache(r.response.tasks || {}, r.response.taskList);
-
- // Check if this is the still the result of the most current request.
- if (this.view != 'tasks' ||
- this.eventsLoading['tasks:' + r.response.taskList] != r.response.taskType) {
- return;
- }
- this._insertTasks(r.response.taskType, r.response.taskList);
- },
-
- /**
- * Reads tasks from the cache and inserts them into the view.
- *
- * @param integer taskType The tasks type, (1 = all tasks,
- * 0 = incomplete tasks, 2 = complete tasks,
- * 3 = future tasks, 4 = future and incomplete
- * tasks)
- * @param string tasksList The task list to be drawn
- */
- _insertTasks: function(taskType, taskList)
- {
- $('kronolithViewTasksBody').select('tr[taskList=' + taskList + ']').invoke('remove');
- var tasks = this.tcache.get(taskList);
- $H(tasks).each(function(task) {
- // TODO: Check for the taskType
- this._insertTask(task);
- }, this);
- },
-
- /**
- * Creates the DOM node for a task and inserts it into the view.
- *
- * @param object task A Hash with the task to insert
- */
- _insertTask: function(task)
- {
- var body = $('kronolithViewTasksBody'),
- row = $('kronolithTasksTemplate').cloneNode(true),
- col = row.down(),
- div = col.down();
-
- row.removeAttribute('id');
- row.writeAttribute('taskList', task.value.l);
- row.writeAttribute('taskId', task.key);
- col.addClassName('kronolithTask' + (task.value.cp != 0 ? 'Completed' : ''));
- col.insert(task.value.n);
- if (!Object.isUndefined(task.value.du)) {
- var date = Date.parse(task.value.du),
- now = new Date();
- if (!now.isBefore(date)) {
- col.addClassName('kronolithTaskDue');
- col.insert(new Element('SPAN', { 'class': 'kronolithSep' }).update(' · '));
- col.insert(new Element('SPAN', { 'class': 'kronolithDate' }).update(date.toString(Kronolith.conf.date_format)));
- }
- }
-
- if (!Object.isUndefined(task.value.sd)) {
- col.insert(new Element('SPAN', { 'class': 'kronolithSep' }).update(' · '));
- col.insert(new Element('SPAN', { 'class': 'kronolithInfo' }).update(task.value.sd));
- }
-
- row.insert(col.show());
- this._insertTaskPosition(row, task);
- },
-
- /**
- * Inserts the task row in the correct position.
- *
- * @param Element newRow The new row to be inserted.
- * @param object newTask A Hash with the task being added.
- */
- _insertTaskPosition: function(newRow, newTask)
- {
- var rows = $('kronolithViewTasksBody').select('tr');
- // The first row is a template one, so must be ignored
- for (var i = 1; i < rows.length; i++) {
- var rowTaskList = rows[i].readAttribute('taskList');
- var rowTaskId = rows[i].readAttribute('taskId');
- var rowTask = this.tcache.get(rowTaskList).get(rowTaskId);
-
- // TODO: Assuming that tasks of the same tasklist are already in
- // order
- if (rowTaskList == newTask.value.l) {
- continue;
- }
-
- if (Object.isUndefined(rowTask)) {
- // TODO: Throw error
- return;
- }
- if (!this._isTaskAfter(newTask.value, rowTask)) {
- break;
- }
- }
- rows[--i].insert({ 'after': newRow.show() });
- },
-
- /**
- * Analyzes which task should be drawn first.
- *
- * TODO: Very incomplete, only a dummy version
- */
- _isTaskAfter: function(taskA, taskB)
- {
- // TODO: Make all ordering system
- return (taskA.pr >= taskB.pr);
- },
-
- /**
- * Completes/uncompletes a task.
- *
- * @param string taskList The task list to which the tasks belongs
- * @param string taskId The id of the task
- */
- _toggleCompletion: function(taskList, taskId)
- {
- var task = this.tcache.get(taskList).get(taskId);
- if (Object.isUndefined(task)) {
- this._toggleCompletionClass(taskId);
- // TODO: Show some message?
- return;
- }
- // Update the cache
- task.cp = (task.cp == "1") ? "0": "1";
- },
-
- /**
- * Toggles the CSS class to show that a tasks is completed/uncompleted.
- *
- * @param string taskId The id of the task
- */
- _toggleCompletionClass: function(taskId)
- {
- var row = $(taskId);
- if (row.length == 0) {
- // FIXME: Show some error?
- return;
- }
- var col = row.down('td.kronolithTaskCol', 0), div = col.down('div.kronolithTaskCheckbox', 0);
-
- col.toggleClassName('kronolithTask');
- col.toggleClassName('kronolithTaskCompleted');
- },
-
- /**
- * Parses a date attribute string into a Date object.
- *
- * For other strings use Date.parse().
- *
- * @param string date A yyyyMMdd date string.
- *
- * @return Date A date object.
- */
- parseDate: function(date)
- {
- return new Date(date.substr(0, 4), date.substr(4, 2) - 1, date.substr(6, 2));
- },
-
- /**
- * Calculates first and last days being displayed.
- *
- * @var Date date The date of the view.
- * @var string view A view name.
- *
- * @return array Array with first and last day of the view.
- */
- viewDates: function(date, view)
- {
- var start = date.clone(), end = date.clone();
-
- switch (view) {
- case 'week':
- start.moveToBeginOfWeek(Kronolith.conf.week_start);
- end.moveToEndOfWeek(Kronolith.conf.week_start);
- break;
- case 'month':
- start.setDate(1);
- start.moveToBeginOfWeek(Kronolith.conf.week_start);
- end.moveToLastDayOfMonth();
- end.moveToEndOfWeek(Kronolith.conf.week_start);
- break;
- case 'year':
- start.setDate(1);
- start.setMonth(0);
- end.setMonth(11);
- end.moveToLastDayOfMonth();
- break;
- case 'agenda':
- end.add(6).days();
- break;
- }
-
- return [start, end];
- },
-
- /**
- * Stores a set of events in the cache.
- *
- * For dates in the specified date ranges that don't contain any events,
- * empty cache entries are created so that those dates aren't re-fetched
- * each time.
- *
- * @param object events A list of calendars and events as returned from
- * an ajax request.
- * @param string calendar A calendar string or array.
- * @param string dates A date range in the format yyyymmddyyyymmdd as
- * used in the ajax response signature.
- */
- _storeCache: function(events, calendar, dates)
- {
- if (Object.isString(calendar)) {
- calendar = calendar.split('|');
- }
-
- // Create cache entry for the calendar.
- if (!this.ecache.get(calendar[0])) {
- this.ecache.set(calendar[0], $H());
- }
- if (!this.ecache.get(calendar[0]).get(calendar[1])) {
- this.ecache.get(calendar[0]).set(calendar[1], $H());
- }
- var calHash = this.ecache.get(calendar[0]).get(calendar[1]);
-
- // Create empty cache entries for all dates.
- if (typeof dates != 'undefined') {
- var day = dates[0].clone(), date;
- while (!day.isAfter(dates[1])) {
- date = day.dateString();
- if (!calHash.get(date)) {
- calHash.set(date, $H());
- }
- day.add(1).day();
- }
- }
-
- var cal = calendar.join('|');
- $H(events).each(function(date) {
- // Store calendar string and other useful information in event
- // objects.
- $H(date.value).each(function(event) {
- event.value.calendar = cal;
- event.value.start = Date.parse(event.value.s);
- event.value.end = Date.parse(event.value.e);
- event.value.sort = event.value.start.toString('HHmmss')
- + (240000 - parseInt(event.value.end.toString('HHmmss'))).toPaddedString(6);
- });
-
- // Store events in cache.
- calHash.set(date.key, calHash.get(date.key).merge(date.value));
- });
- },
-
- /**
- * Stores a set of tasks in the cache.
- *
- * @param Hash tasks The tasks to be stored
- * @param string taskList The task list to which the tasks belong
- */
- _storeTasksCache: function(tasks, taskList)
- {
- if (!this.tcache.get(taskList)) {
- this.tcache.set(taskList, $H());
- }
-
- var taskHash = this.tcache.get(taskList);
-
- $H(tasks).each(function(task) {
- taskHash.set(task.key, task.value);
- });
- },
-
- /**
- * Deletes an event from the cache.
- *
- * @param string event An event ID.
- * @param string calendar A calendar string or array.
- */
- _deleteCache: function(event, calendar)
- {
- if (Object.isString(calendar)) {
- calendar = calendar.split('|');
- }
- if (!this.ecache.get(calendar[0]) ||
- !this.ecache.get(calendar[0]).get(calendar[1])) {
- return;
- }
- this.ecache.get(calendar[0]).get(calendar[1]).each(function(day) {
- delete day.value[event];
- });
- },
-
- /**
- * Return all events for a single day from all displayed calendars merged
- * into a single hash.
- *
- * @param string date A yyyymmdd date string.
- *
- * @return Hash An event hash which event ids as keys and event objects as
- * values.
- */
- _getCacheForDate: function(date)
- {
- var events = $H();
- this.ecache.each(function(type) {
- type.value.each(function(cal) {
- if (!Kronolith.conf.calendars[type.key][cal.key].show) {
- return;
- }
- events = events.merge(cal.value.get(date));
- });
- });
- return events;
- },
-
- /**
- * Helper method for Enumerable.sortBy to sort events first by start time,
- * second by end time reversed.
- *
- * @param Hash event A hash entry with the event object as the value.
- *
- * @return string A comparable string.
- */
- _sortEvents: function(event)
- {
- return event.value.sort;
- },
-
- _addHistory: function(loc, data)
- {
- if (Horde.dhtmlHistory.getCurrentLocation() != loc) {
- Horde.dhtmlHistory.add(loc, data);
- }
- },
-
- iframeContent: function(name, loc)
- {
- if (name === null) {
- name = loc;
- }
-
- var container = $('dimpmain_portal'), iframe;
- if (!container) {
- this.showNotifications([ { type: 'horde.error', message: 'Bad portal!' } ]);
- return;
- }
-
- iframe = new Element('IFRAME', { id: 'iframe' + name, className: 'iframe', frameBorder: 0, src: loc });
- this._resizeIE6Iframe(iframe);
-
- // Hide menu in prefs pages.
- if (name == 'options') {
- iframe.observe('load', function() { $('iframeoptions').contentWindow.document.getElementById('menu').style.display = 'none'; });
- }
-
- container.insert(iframe);
- },
-
- onResize: function(noupdate, nowait)
- {
- },
-
- /* Keydown event handler */
- keydownHandler: function(e)
- {
- var kc = e.keyCode || e.charCode;
-
- form = e.findElement('FORM');
- if (form) {
- switch (kc) {
- case Event.KEY_RETURN:
- switch (form.identify()) {
- case 'kronolithEventForm':
- this.saveEvent();
- e.stop();
- break;
-
- case 'kronolithSearchForm':
- this.go('search:' + $F('kronolithSearchContext') + ':' + $F('kronolithSearchTerm'))
- e.stop();
- break;
- }
- break;
- }
- return;
- }
-
- switch (kc) {
- case Event.KEY_ESC:
- this._closeRedBox();
- break;
- }
- },
-
- keyupHandler: function(e)
- {
- /*
- if (e.element().readAttribute('id') == 'foo') {
- }
- */
- },
-
- clickHandler: function(e, dblclick)
- {
- if (e.isRightClick()) {
- return;
- }
-
- var elt = e.element(),
- orig = e.element(),
- id, tmp, calendar, calendarClass;
-
- while (Object.isElement(elt)) {
- id = elt.readAttribute('id');
-
- switch (id) {
- case 'kronolithLogo':
- this.go('portal');
- e.stop();
- return;
-
- case 'id_fullday':
- this.eventForm.select('.edit_at').each(Element.toggle);
- e.stop();
- return;
-
- case 'kronolithNewEvent':
- this.go('event');
- e.stop();
- return;
-
- case 'kronolithEventSave':
- this.saveEvent();
- e.stop();
- return;
-
- case 'kronolithEventDelete':
- var cal = $F('kronolithEventCalendar'),
- eventid = $F('kronolithEventId');
- this.doAction('DeleteEvent',
- { 'cal': cal, 'id': eventid },
- function(r) {
- if (r.response.deleted) {
- this._removeEvent(eventid, cal);
- } else {
- $('kronolithBody').select('div[calendar=' + cal + '][eventid=' + eventid + ']').invoke('toggle');
- }
- }.bind(this));
- $('kronolithBody').select('div[calendar=' + cal + '][eventid=' + eventid + ']').invoke('hide');
- this._closeRedBox();
- e.stop();
- return;
-
- case 'kronolithEventCancel':
- this._closeRedBox();
- e.stop();
- return;
-
- case 'kronolithNavDay':
- case 'kronolithNavWeek':
- case 'kronolithNavMonth':
- case 'kronolithNavYear':
- case 'kronolithNavTasks':
- case 'kronolithNavAgenda':
- this.go(id.substring(12).toLowerCase() + ':' + this.date.dateString());
- e.stop();
- return;
-
- case 'kronolithMinicalDate':
- this.go('month:' + orig.readAttribute('date'));
- e.stop();
- return;
-
- case 'kronolithMinical':
- if (orig.id == 'kronolithMinicalPrev') {
- var date = this.parseDate($('kronolithMinicalDate').readAttribute('date'));
- date.previous().month();
- this.updateMinical(date);
- e.stop();
- return;
- }
- if (orig.id == 'kronolithMinicalNext') {
- var date = this.parseDate($('kronolithMinicalDate').readAttribute('date'));
- date.next().month();
- this.updateMinical(date);
- e.stop();
- return;
- }
-
- var tmp = orig;
- if (tmp.tagName != 'td') {
- tmp.up('td');
- }
- if (tmp) {
- if (tmp.readAttribute('weekdate') &&
- tmp.hasClassName('kronolithMinicalWeek')) {
- this.go('week:' + tmp.readAttribute('weekdate'));
- } else if (tmp.readAttribute('date') &&
- !tmp.hasClassName('empty')) {
- this.go('day:' + tmp.readAttribute('date'));
- }
- }
- e.stop();
- return;
-
- case 'kronolithViewMonth':
- if (orig.hasClassName('kronolithFirstCol')) {
- var date = orig.readAttribute('date');
- if (date) {
- this.go('week:' + date);
- e.stop();
- return;
- }
- } else if (orig.hasClassName('kronolithDay')) {
- var date = orig.readAttribute('date');
- if (date) {
- this.go('day:' + date);
- e.stop();
- return;
- }
- }
- e.stop();
- return;
-
- case 'kronolithViewYear':
- var tmp = orig;
- if (tmp.tagName != 'td') {
- tmp.up('td');
- }
- if (tmp) {
- if (tmp.readAttribute('weekdate') &&
- tmp.hasClassName('kronolithMinicalWeek')) {
- this.go('week:' + tmp.readAttribute('weekdate'));
- } else if (tmp.hasClassName('kronolithMinicalDate')) {
- this.go('month:' + tmp.readAttribute('date'));
- } else if (tmp.readAttribute('date') &&
- !tmp.hasClassName('empty')) {
- this.go('day:' + tmp.readAttribute('date'));
- }
- }
- e.stop();
- return;
-
- case 'kronolithViewAgenda':
- var tmp = orig;
- if (tmp.tagName != 'td') {
- tmp.up('td');
- }
- if (tmp && tmp.readAttribute('date')) {
- this.go('day:' + tmp.readAttribute('date'));
- }
- e.stop();
- return;
-
- case 'kronolithSearchButton':
- this.go('search:' + $F('kronolithSearchContext') + ':' + $F('kronolithSearchTerm'))
- break;
-
- case 'alertsloglink':
- tmp = $('alertsloglink').down('A');
- if (this.Growler.toggleLog()) {
- tmp.update(DIMP.text.hidealog);
- } else {
- tmp.update(DIMP.text.showalog);
- }
- break;
- }
-
- // Caution, this only works if the element has definitely only a
- // single CSS class.
- switch (elt.className) {
- case 'kronolithGotoToday':
- this.go(this.view + ':' + new Date().dateString());
- e.stop();
- return;
-
- case 'kronolithPrev':
- case 'kronolithNext':
- var newDate = this.date.clone(),
- offset = elt.className == 'kronolithPrev' ? -1 : 1;
- switch (this.view) {
- case 'day':
- case 'agenda':
- newDate.add(offset).day();
- break;
- case 'week':
- newDate.add(offset).week();
- break;
- case 'month':
- newDate.add(offset).month();
- break;
- case 'year':
- newDate.add(offset).year();
- break;
- }
- this.go(this.view + ':' + newDate.dateString());
- e.stop();
- return;
-
- case 'kronolithAddEvent':
- this.go('event:' + elt.readAttribute('date'));
- e.stop();
- return;
-
- case 'kronolithEventTag':
- $('kronolithEventTags').autocompleter.addNewItemNode(elt.getText());
- e.stop();
- return;
- }
-
- if (elt.hasClassName('kronolithEvent')) {
- this.go('event:' + elt.readAttribute('calendar') + ':' + elt.readAttribute('eventid'));
- e.stop();
- return;
- } else if (elt.hasClassName('kronolithWeekDay')) {
- this.go('day:' + elt.readAttribute('date'));
- e.stop();
- return;
- } else if (elt.hasClassName('kronolithTaskCheckbox')) {
- var taskId = elt.up('tr.kronolithTaskRow', 0).readAttribute('id'),
- taskList = elt.up('tr.kronolithTaskRow', 0).readAttribute('tasklist');
- this._toggleCompletionClass(taskId);
- this.doAction('ToggleCompletion',
- { taskList: taskList, taskType: this.taskType, taskId: taskId },
- function(r) {
- if (r.response.toggled) {
- this._toggleCompletion(taskList, taskId);
- } else {
- // Check if this is the still the result
- // of the most current request.
- if (this.view != 'tasks' || this.taskType != r.response.taskType) {
- return;
- }
- this._toggleCompletionClass(taskId);
- }
- }.bind(this));
- e.stop();
- return;
- }
-
- calClass = elt.readAttribute('calendarclass');
- if (calClass) {
- var calendar = elt.readAttribute('calendar');
- Kronolith.conf.calendars[calClass][calendar].show = !Kronolith.conf.calendars[calClass][calendar].show;
- if (this.view == 'year' ||
- typeof this.ecache.get(calClass) == 'undefined' ||
- typeof this.ecache.get(calClass).get(calendar) == 'undefined') {
- var dates = this.viewDates(this.date, this.view);
- this._loadEvents(dates[0], dates[1], this.view, [[calClass, calendar]]);
- } else {
- $('kronolithBody').select('div[calendar=' + calClass + '|' + calendar + ']').invoke('toggle');
- }
- elt.toggleClassName('kronolithCalOn');
- elt.toggleClassName('kronolithCalOff');
- if (calClass == 'remote' || calClass == 'external') {
- if (calClass == 'external' && calendar.startsWith('tasks/')) {
- var taskList = calendar.substr(6);
- if (typeof this.tcache.get(taskList) == 'undefined' &&
- this.view == 'tasks') {
- this._loadTasks(this.taskType,[taskList]);
- } else {
- $('kronolithViewTasksBody').select('tr[taskList=' + taskList + ']').invoke('toggle');
- }
- }
- calendar = calClass + '_' + calendar;
- }
- this.doAction('SaveCalPref', { toggle_calendar: calendar });
- }
-
- elt = elt.up();
- }
- // Workaround Firebug bug.
- Prototype.emptyFunction();
- },
-
- mouseHandler: function(e, type)
- {
- /*
- var elt = e.element();
-
- switch (type) {
- case 'over':
- if (DragDrop.Drags.drag && elt.hasClassName('exp')) {
- this._toggleSubFolder(elt.up(), 'exp');
- }
- break;
- }
- */
- },
-
- editEvent: function(calendar, id, date)
- {
- if (Object.isUndefined($('kronolithEventTags').autocompleter)) {
- this.editEvent.bind(this, calendar, id, date).defer();
- return;
- }
-
- RedBox.onDisplay = function() {
- try {
- $('kronolithEventForm').focusFirstElement();
- } catch(e) {}
- RedBox.onDisplay = null;
- };
-
- $('kronolithEventTags').autocompleter.init();
- $('kronolithEventForm').enable();
- $('kronolithEventForm').reset();
- this.doAction('ListTopTags', {}, this._topTags);
- if (id) {
- RedBox.loading();
- this.doAction('GetEvent', { 'cal': calendar, 'id': id }, this._editEvent.bind(this));
- } else {
- var d = date ? this.parseDate(date) : new Date();
- $('kronolithEventId').value = '';
- $('kronolithEventCalendar').value = Kronolith.conf.default_calendar;
- $('kronolithEventDelete').hide();
- $('kronolithEventStartDate').value = d.toString(Kronolith.conf.date_format);
- $('kronolithEventStartTime').value = d.toString(Kronolith.conf.time_format);
- d.add(1).hour();
- $('kronolithEventEndDate').value = d.toString(Kronolith.conf.date_format);
- $('kronolithEventEndTime').value = d.toString(Kronolith.conf.time_format);
- RedBox.showHtml($('kronolithEventDialog').show());
- this.eventForm = RedBox.getWindowContents();
- }
- },
-
- saveEvent: function()
- {
- var cal = $F('kronolithEventCalendar'),
- eventid = $F('kronolithEventId'),
- viewDates = this.viewDates(this.date, this.view),
- start = viewDates[0].dateString(),
- end = viewDates[1].dateString();
- this.startLoading(cal, start, end);
- this.doAction('SaveEvent',
- $H($('kronolithEventForm').serialize({ 'hash': true }))
- .merge({
- 'view': this.view,
- 'view_start': start,
- 'view_end': end
- }),
- function(r) {
- if (r.response.events && eventid) {
- this._removeEvent(eventid, cal);
- }
- this._loadEventsCallback(r);
- this._closeRedBox();
- }.bind(this));
- },
-
- _topTags: function(r)
- {
- if (!r.response.tags) {
- $('kronolithEventTopTags').update();
- return;
- }
- t = new Element('div', {});
- r.response.tags.each(function(tag) {
- t.insert(new Element('span', { 'class': 'kronolithEventTag' }).update(tag));
- });
- $('kronolithEventTopTags').update(t);
- return;
- },
-
- /**
- * Callback method for showing event forms.
- *
- * @param object r The ajax response object.
- */
- _editEvent: function(r)
- {
- if (!r.response.event) {
- RedBox.close();
- return;
- }
-
- var ev = r.response.event;
- $('kronolithEventId').value = ev.id;
- $('kronolithEventCalendar').value = ev.ty + '|' + ev.c;
- $('kronolithEventTitle').value = ev.t;
- $('kronolithEventLocation').value = ev.l;
- $('kronolithEventAllday').checked = ev.al;
- $('kronolithEventStartDate').value = ev.sd
- $('kronolithEventStartTime').value = ev.st;
- $('kronolithEventEndDate').value = ev.ed;
- $('kronolithEventEndTime').value = ev.et;
- $('kronolithEventTags').autocompleter.init(ev.tg);
- if (ev.r) {
- // @todo: refine
- $A($('kronolithEventRecurrence').options).find(function(option) {
- return option.value == ev.r || option.value == -1;
- }).selected = true;
- }
- if (ev.pe) {
- $('kronolithEventSave').show();
- $('kronolithEventForm').enable();
- } else {
- $('kronolithEventSave').hide();
- $('kronolithEventForm').disable();
- $('kronolithEventCancel').enable();
- }
- if (ev.pd) {
- $('kronolithEventDelete').show();
- } else {
- $('kronolithEventDelete').hide();
- }
-
- RedBox.showHtml($('kronolithEventDialog').show());
- this.eventForm = RedBox.getWindowContents();
- },
-
- _closeRedBox: function()
- {
- RedBox.close();
- this.eventForm = null;
- },
-
- /* Onload function. */
- onDomLoad: function()
- {
- if (typeof ContextSensitive != 'undefined') {
- this.DMenu = new ContextSensitive({ onClick: this.contextOnClick, onShow: this.contextOnShow });
- }
-
- document.observe('keydown', KronolithCore.keydownHandler.bindAsEventListener(KronolithCore));
- document.observe('keyup', KronolithCore.keyupHandler.bindAsEventListener(KronolithCore));
- document.observe('click', KronolithCore.clickHandler.bindAsEventListener(KronolithCore));
- document.observe('dblclick', KronolithCore.clickHandler.bindAsEventListener(KronolithCore, true));
- document.observe('mouseover', KronolithCore.mouseHandler.bindAsEventListener(KronolithCore, 'over'));
-
- if (Horde.dhtmlHistory.initialize()) {
- Horde.dhtmlHistory.addListener(this.go.bind(this));
- }
-
- this.updateCalendarList();
-
- /* Initialize the starting page if necessary. addListener() will have
- * already fired if there is a current location so only do a go()
- * call if there is no current location. */
- if (!Horde.dhtmlHistory.getCurrentLocation()) {
- this.go(Kronolith.conf.login_view);
- }
-
- $('kronolithMenu').select('div.kronolithCalendars div').each(function(s) {
- s.observe('mouseover', s.addClassName.curry('kronolithCalOver'));
- s.observe('mouseout', s.removeClassName.curry('kronolithCalOver'));
- });
-
- /* Add Growler notifications. */
- this.Growler = new Growler({
- location: 'br',
- log: true,
- noalerts: Kronolith.text.noalerts
- });
-
- if (Kronolith.conf.is_ie6) {
- /* Disable text selection in preview pane for IE 6. */
- document.observe('selectstart', Event.stop);
-
- /* Since IE 6 doesn't support hover over non-links, use javascript
- * events to replicate mouseover CSS behavior. */
- $('foobar').compact().invoke('select', 'LI').flatten().compact().each(function(e) {
- e.observe('mouseover', e.addClassName.curry('over')).observe('mouseout', e.removeClassName.curry('over'));
- });
- }
- },
-
- toggleCalendar: function(elm)
- {
- elm.toggleClassName('on');
- },
-
- // By default, no context onShow action
- contextOnShow: Prototype.emptyFunction,
-
- // By default, no context onClick action
- contextOnClick: Prototype.emptyFunction
-
-};
-
-/* Initialize global event handlers. */
-document.observe('dom:loaded', KronolithCore.onDomLoad.bind(KronolithCore));
-Event.observe(window, 'resize', KronolithCore.onResize.bind(KronolithCore));
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "lt-LT",
- englishName: "Lithuanian (Lithuania)",
- nativeName: "lietuvių (Lietuva)",
-
- /* Day Name Strings */
- dayNames: ["sekmadienis", "pirmadienis", "antradienis", "trečiadienis", "ketvirtadienis", "penktadienis", "šeštadienis"],
- abbreviatedDayNames: ["Sk", "Pr", "An", "Tr", "Kt", "Pn", "Št"],
- shortestDayNames: ["S", "P", "A", "T", "K", "Pn", "Š"],
- firstLetterDayNames: ["S", "P", "A", "T", "K", "P", "Š"],
-
- /* Month Name Strings */
- monthNames: ["sausis", "vasaris", "kovas", "balandis", "gegužė", "birželis", "liepa", "rugpjūtis", "rugsėjis", "spalis", "lapkritis", "gruodis"],
- abbreviatedMonthNames: ["Sau", "Vas", "Kov", "Bal", "Geg", "Bir", "Lie", "Rgp", "Rgs", "Spl", "Lap", "Grd"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "ymd",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "yyyy.MM.dd",
- longDate: "yyyy 'm.' MMMM d 'd.'",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "yyyy 'm.' MMMM d 'd.' HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "MMMM d 'd.'",
- yearMonth: "yyyy 'm.' MMMM"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^sau(sis)?/i,
- feb: /^vas(aris)?/i,
- mar: /^kov(as)?/i,
- apr: /^bal(andis)?/i,
- may: /^geg(užė)?/i,
- jun: /^bir(želis)?/i,
- jul: /^lie(pa)?/i,
- aug: /^rugpjūtis/i,
- sep: /^rugsėjis/i,
- oct: /^spalis/i,
- nov: /^lap(kritis)?/i,
- dec: /^gruodis/i,
-
- sun: /^s(k(kmadienis)?)?/i,
- mon: /^p(r(rmadienis)?)?/i,
- tue: /^a(n(tradienis)?)?/i,
- wed: /^t(r(ečiadienis)?)?/i,
- thu: /^k(t(tvirtadienis)?)?/i,
- fri: /^penktadienis/i,
- sat: /^š(t(štadienis)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "lv-LV",
- englishName: "Latvian (Latvia)",
- nativeName: "latviešu (Latvija)",
-
- /* Day Name Strings */
- dayNames: ["svētdiena", "pirmdiena", "otrdiena", "trešdiena", "ceturtdiena", "piektdiena", "sestdiena"],
- abbreviatedDayNames: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "Se"],
- shortestDayNames: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "Se"],
- firstLetterDayNames: ["S", "P", "O", "T", "C", "P", "S"],
-
- /* Month Name Strings */
- monthNames: ["janvāris", "februāris", "marts", "aprīlis", "maijs", "jūnijs", "jūlijs", "augusts", "septembris", "oktobris", "novembris", "decembris"],
- abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jūn", "Jūl", "Aug", "Sep", "Okt", "Nov", "Dec"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "ymd",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "yyyy.MM.dd.",
- longDate: "dddd, yyyy'. gada 'd. MMMM",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "dddd, yyyy'. gada 'd. MMMM H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "d. MMMM",
- yearMonth: "yyyy. MMMM"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(vāris)?/i,
- feb: /^feb(ruāris)?/i,
- mar: /^mar(ts)?/i,
- apr: /^apr(īlis)?/i,
- may: /^mai(js)?/i,
- jun: /^jūn(ijs)?/i,
- jul: /^jūl(ijs)?/i,
- aug: /^aug(usts)?/i,
- sep: /^sep(tembris)?/i,
- oct: /^okt(obris)?/i,
- nov: /^nov(embris)?/i,
- dec: /^dec(embris)?/i,
-
- sun: /^svētdiena/i,
- mon: /^pirmdiena/i,
- tue: /^otrdiena/i,
- wed: /^trešdiena/i,
- thu: /^ceturtdiena/i,
- fri: /^piektdiena/i,
- sat: /^sestdiena/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "mk-MK",
- englishName: "Macedonian (Former Yugoslav Republic of Macedonia)",
- nativeName: "македонски јазик (Македонија)",
-
- /* Day Name Strings */
- dayNames: ["недела", "понеделник", "вторник", "среда", "четврток", "петок", "сабота"],
- abbreviatedDayNames: ["нед", "пон", "втр", "срд", "чет", "пет", "саб"],
- shortestDayNames: ["не", "по", "вт", "ср", "че", "пе", "са"],
- firstLetterDayNames: ["н", "п", "в", "с", "ч", "п", "с"],
-
- /* Month Name Strings */
- monthNames: ["јануари", "февруари", "март", "април", "мај", "јуни", "јули", "август", "септември", "октомври", "ноември", "декември"],
- abbreviatedMonthNames: ["јан", "фев", "мар", "апр", "мај", "јун", "јул", "авг", "сеп", "окт", "ное", "дек"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd.MM.yyyy",
- longDate: "dddd, dd MMMM yyyy",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "dddd, dd MMMM yyyy HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^јан(уари)?/i,
- feb: /^фев(руари)?/i,
- mar: /^мар(т)?/i,
- apr: /^апр(ил)?/i,
- may: /^мај/i,
- jun: /^јун(и)?/i,
- jul: /^јул(и)?/i,
- aug: /^авг(уст)?/i,
- sep: /^сеп(тември)?/i,
- oct: /^окт(омври)?/i,
- nov: /^ное(мври)?/i,
- dec: /^дек(ември)?/i,
-
- sun: /^не(д(ела)?)?/i,
- mon: /^по(н(еделник)?)?/i,
- tue: /^вт(р(рник)?)?/i,
- wed: /^ср(д(да)?)?/i,
- thu: /^че(т(врток)?)?/i,
- fri: /^пе(т(ок)?)?/i,
- sat: /^са(б(ота)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "nb-NO",
- englishName: "Norwegian, Bokmål (Norway)",
- nativeName: "norsk, bokmål (Norge)",
-
- /* Day Name Strings */
- dayNames: ["søndag", "mandag", "tirsdag", "onsdag", "torsdag", "fredag", "lørdag"],
- abbreviatedDayNames: ["sø", "ma", "ti", "on", "to", "fr", "lø"],
- shortestDayNames: ["sø", "ma", "ti", "on", "to", "fr", "lø"],
- firstLetterDayNames: ["s", "m", "t", "o", "t", "f", "l"],
-
- /* Month Name Strings */
- monthNames: ["januar", "februar", "mars", "april", "mai", "juni", "juli", "august", "september", "oktober", "november", "desember"],
- abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "mai", "jun", "jul", "aug", "sep", "okt", "nov", "des"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd.MM.yyyy",
- longDate: "d. MMMM yyyy",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "d. MMMM yyyy HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "d. MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(uar)?/i,
- feb: /^feb(ruar)?/i,
- mar: /^mar(s)?/i,
- apr: /^apr(il)?/i,
- may: /^mai/i,
- jun: /^jun(i)?/i,
- jul: /^jul(i)?/i,
- aug: /^aug(ust)?/i,
- sep: /^sep(t(ember)?)?/i,
- oct: /^okt(ober)?/i,
- nov: /^nov(ember)?/i,
- dec: /^des(ember)?/i,
-
- sun: /^søndag/i,
- mon: /^mandag/i,
- tue: /^tirsdag/i,
- wed: /^onsdag/i,
- thu: /^torsdag/i,
- fri: /^fredag/i,
- sat: /^lørdag/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "nl-NL",
- englishName: "Dutch (Netherlands)",
- nativeName: "Nederlands (Nederland)",
-
- /* Day Name Strings */
- dayNames: ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"],
- abbreviatedDayNames: ["zo", "ma", "di", "wo", "do", "vr", "za"],
- shortestDayNames: ["zo", "ma", "di", "wo", "do", "vr", "za"],
- firstLetterDayNames: ["z", "m", "d", "w", "d", "v", "z"],
-
- /* Month Name Strings */
- monthNames: ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"],
- abbreviatedMonthNames: ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "d-M-yyyy",
- longDate: "dddd d MMMM yyyy",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "dddd d MMMM yyyy H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(uari)?/i,
- feb: /^feb(ruari)?/i,
- mar: /^maart/i,
- apr: /^apr(il)?/i,
- may: /^mei/i,
- jun: /^jun(i)?/i,
- jul: /^jul(i)?/i,
- aug: /^aug(ustus)?/i,
- sep: /^sep(t(ember)?)?/i,
- oct: /^okt(ober)?/i,
- nov: /^nov(ember)?/i,
- dec: /^dec(ember)?/i,
-
- sun: /^zondag/i,
- mon: /^maandag/i,
- tue: /^dinsdag/i,
- wed: /^woensdag/i,
- thu: /^donderdag/i,
- fri: /^vrijdag/i,
- sat: /^zaterdag/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "nn-NO",
- englishName: "Norwegian, Nynorsk (Norway)",
- nativeName: "norsk, nynorsk (Noreg)",
-
- /* Day Name Strings */
- dayNames: ["søndag", "måndag", "tysdag", "onsdag", "torsdag", "fredag", "laurdag"],
- abbreviatedDayNames: ["sø", "må", "ty", "on", "to", "fr", "la"],
- shortestDayNames: ["sø", "må", "ty", "on", "to", "fr", "la"],
- firstLetterDayNames: ["s", "m", "t", "o", "t", "f", "l"],
-
- /* Month Name Strings */
- monthNames: ["januar", "februar", "mars", "april", "mai", "juni", "juli", "august", "september", "oktober", "november", "desember"],
- abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "mai", "jun", "jul", "aug", "sep", "okt", "nov", "des"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd.MM.yyyy",
- longDate: "d. MMMM yyyy",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "d. MMMM yyyy HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "d. MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(uar)?/i,
- feb: /^feb(ruar)?/i,
- mar: /^mar(s)?/i,
- apr: /^apr(il)?/i,
- may: /^mai/i,
- jun: /^jun(i)?/i,
- jul: /^jul(i)?/i,
- aug: /^aug(ust)?/i,
- sep: /^sep(t(ember)?)?/i,
- oct: /^okt(ober)?/i,
- nov: /^nov(ember)?/i,
- dec: /^des(ember)?/i,
-
- sun: /^søndag/i,
- mon: /^måndag/i,
- tue: /^tysdag/i,
- wed: /^onsdag/i,
- thu: /^torsdag/i,
- fri: /^fredag/i,
- sat: /^laurdag/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "pl-PL",
- englishName: "Polish (Poland)",
- nativeName: "polski (Polska)",
-
- /* Day Name Strings */
- dayNames: ["niedziela", "poniedziałek", "wtorek", "środa", "czwartek", "piątek", "sobota"],
- abbreviatedDayNames: ["N", "Pn", "Wt", "Śr", "Cz", "Pt", "So"],
- shortestDayNames: ["N", "Pn", "Wt", "Śr", "Cz", "Pt", "So"],
- firstLetterDayNames: ["N", "P", "W", "Ś", "C", "P", "S"],
-
- /* Month Name Strings */
- monthNames: ["styczeń", "luty", "marzec", "kwiecień", "maj", "czerwiec", "lipiec", "sierpień", "wrzesień", "październik", "listopad", "grudzień"],
- abbreviatedMonthNames: ["sty", "lut", "mar", "kwi", "maj", "cze", "lip", "sie", "wrz", "paź", "lis", "gru"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "ymd",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "yyyy-MM-dd",
- longDate: "d MMMM yyyy",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "d MMMM yyyy HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "d MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^sty(czeń)?/i,
- feb: /^lut(y)?/i,
- mar: /^mar(zec)?/i,
- apr: /^kwi(ecień)?/i,
- may: /^maj/i,
- jun: /^cze(rwiec)?/i,
- jul: /^lip(iec)?/i,
- aug: /^sie(rpień)?/i,
- sep: /^wrz(esień)?/i,
- oct: /^paź(dziernik)?/i,
- nov: /^lis(topad)?/i,
- dec: /^gru(dzień)?/i,
-
- sun: /^niedziela/i,
- mon: /^poniedziałek/i,
- tue: /^wtorek/i,
- wed: /^środa/i,
- thu: /^czwartek/i,
- fri: /^piątek/i,
- sat: /^sobota/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "pt-BR",
- englishName: "Portuguese (Brazil)",
- nativeName: "Português (Brasil)",
-
- /* Day Name Strings */
- dayNames: ["domingo", "segunda-feira", "terça-feira", "quarta-feira", "quinta-feira", "sexta-feira", "sábado"],
- abbreviatedDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"],
- shortestDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"],
- firstLetterDayNames: ["d", "s", "t", "q", "q", "s", "s"],
-
- /* Month Name Strings */
- monthNames: ["janeiro", "fevereiro", "março", "abril", "maio", "junho", "julho", "agosto", "setembro", "outubro", "novembro", "dezembro"],
- abbreviatedMonthNames: ["jan", "fev", "mar", "abr", "mai", "jun", "jul", "ago", "set", "out", "nov", "dez"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 0,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "d/M/yyyy",
- longDate: "dddd, d' de 'MMMM' de 'yyyy",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "dddd, d' de 'MMMM' de 'yyyy H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd' de 'MMMM",
- yearMonth: "MMMM' de 'yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(eiro)?/i,
- feb: /^fev(ereiro)?/i,
- mar: /^mar(ço)?/i,
- apr: /^abr(il)?/i,
- may: /^mai(o)?/i,
- jun: /^jun(ho)?/i,
- jul: /^jul(ho)?/i,
- aug: /^ago(sto)?/i,
- sep: /^set(embro)?/i,
- oct: /^out(ubro)?/i,
- nov: /^nov(embro)?/i,
- dec: /^dez(embro)?/i,
-
- sun: /^domingo/i,
- mon: /^segunda-feira/i,
- tue: /^terça-feira/i,
- wed: /^quarta-feira/i,
- thu: /^quinta-feira/i,
- fri: /^sexta-feira/i,
- sat: /^sábado/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "pt-PT",
- englishName: "Portuguese (Portugal)",
- nativeName: "português (Portugal)",
-
- /* Day Name Strings */
- dayNames: ["domingo", "segunda-feira", "terça-feira", "quarta-feira", "quinta-feira", "sexta-feira", "sábado"],
- abbreviatedDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"],
- shortestDayNames: ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"],
- firstLetterDayNames: ["d", "s", "t", "q", "q", "s", "s"],
-
- /* Month Name Strings */
- monthNames: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"],
- abbreviatedMonthNames: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd-MM-yyyy",
- longDate: "dddd, d' de 'MMMM' de 'yyyy",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "dddd, d' de 'MMMM' de 'yyyy H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "d/M",
- yearMonth: "MMMM' de 'yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(eiro)?/i,
- feb: /^fev(ereiro)?/i,
- mar: /^mar(ço)?/i,
- apr: /^abr(il)?/i,
- may: /^mai(o)?/i,
- jun: /^jun(ho)?/i,
- jul: /^jul(ho)?/i,
- aug: /^ago(sto)?/i,
- sep: /^set(embro)?/i,
- oct: /^out(ubro)?/i,
- nov: /^nov(embro)?/i,
- dec: /^dez(embro)?/i,
-
- sun: /^domingo/i,
- mon: /^segunda-feira/i,
- tue: /^terça-feira/i,
- wed: /^quarta-feira/i,
- thu: /^quinta-feira/i,
- fri: /^sexta-feira/i,
- sat: /^sábado/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "ro-RO",
- englishName: "Romanian (Romania)",
- nativeName: "română (România)",
-
- /* Day Name Strings */
- dayNames: ["duminică", "luni", "marţi", "miercuri", "joi", "vineri", "sâmbătă"],
- abbreviatedDayNames: ["D", "L", "Ma", "Mi", "J", "V", "S"],
- shortestDayNames: ["D", "L", "Ma", "Mi", "J", "V", "S"],
- firstLetterDayNames: ["D", "L", "M", "M", "J", "V", "S"],
-
- /* Month Name Strings */
- monthNames: ["ianuarie", "februarie", "martie", "aprilie", "mai", "iunie", "iulie", "august", "septembrie", "octombrie", "noiembrie", "decembrie"],
- abbreviatedMonthNames: ["ian.", "feb.", "mar.", "apr.", "mai.", "iun.", "iul.", "aug.", "sep.", "oct.", "nov.", "dec."],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd.MM.yyyy",
- longDate: "d MMMM yyyy",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "d MMMM yyyy HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "d MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^ian(.(uarie)?)?/i,
- feb: /^feb(.(ruarie)?)?/i,
- mar: /^mar(.(tie)?)?/i,
- apr: /^apr(.(ilie)?)?/i,
- may: /^mai(.()?)?/i,
- jun: /^iun(.(ie)?)?/i,
- jul: /^iul(.(ie)?)?/i,
- aug: /^aug(.(ust)?)?/i,
- sep: /^sep(.(tembrie)?)?/i,
- oct: /^oct(.(ombrie)?)?/i,
- nov: /^noiembrie/i,
- dec: /^dec(.(embrie)?)?/i,
-
- sun: /^duminică/i,
- mon: /^luni/i,
- tue: /^marţi/i,
- wed: /^miercuri/i,
- thu: /^joi/i,
- fri: /^vineri/i,
- sat: /^sâmbătă/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "ru-RU",
- englishName: "Russian (Russia)",
- nativeName: "русский (Россия)",
-
- /* Day Name Strings */
- dayNames: ["воскресенье", "понедельник", "вторник", "среда", "четверг", "пятница", "суббота"],
- abbreviatedDayNames: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
- shortestDayNames: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
- firstLetterDayNames: ["В", "П", "В", "С", "Ч", "П", "С"],
-
- /* Month Name Strings */
- monthNames: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"],
- abbreviatedMonthNames: ["янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd.MM.yyyy",
- longDate: "d MMMM yyyy 'г.'",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "d MMMM yyyy 'г.' H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "MMMM dd",
- yearMonth: "MMMM yyyy 'г.'"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^янв(арь)?/i,
- feb: /^фев(раль)?/i,
- mar: /^мар(т)?/i,
- apr: /^апр(ель)?/i,
- may: /^май/i,
- jun: /^июн(ь)?/i,
- jul: /^июл(ь)?/i,
- aug: /^авг(уст)?/i,
- sep: /^сен(тябрь)?/i,
- oct: /^окт(ябрь)?/i,
- nov: /^ноя(брь)?/i,
- dec: /^дек(абрь)?/i,
-
- sun: /^воскресенье/i,
- mon: /^понедельник/i,
- tue: /^вторник/i,
- wed: /^среда/i,
- thu: /^четверг/i,
- fri: /^пятница/i,
- sat: /^суббота/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "sk-SK",
- englishName: "Slovak (Slovakia)",
- nativeName: "slovenčina (Slovenská republika)",
-
- /* Day Name Strings */
- dayNames: ["nedeľa", "pondelok", "utorok", "streda", "štvrtok", "piatok", "sobota"],
- abbreviatedDayNames: ["ne", "po", "ut", "st", "št", "pi", "so"],
- shortestDayNames: ["ne", "po", "ut", "st", "št", "pi", "so"],
- firstLetterDayNames: ["n", "p", "u", "s", "š", "p", "s"],
-
- /* Month Name Strings */
- monthNames: ["január", "február", "marec", "apríl", "máj", "jún", "júl", "august", "september", "október", "november", "december"],
- abbreviatedMonthNames: ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "d. M. yyyy",
- longDate: "d. MMMM yyyy",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "d. MMMM yyyy H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^január/i,
- feb: /^február/i,
- mar: /^marec/i,
- apr: /^apríl/i,
- may: /^máj/i,
- jun: /^jún/i,
- jul: /^júl/i,
- aug: /^august/i,
- sep: /^sep(t(ember)?)?/i,
- oct: /^október/i,
- nov: /^november/i,
- dec: /^december/i,
-
- sun: /^nedeľa/i,
- mon: /^pondelok/i,
- tue: /^utorok/i,
- wed: /^streda/i,
- thu: /^štvrtok/i,
- fri: /^piatok/i,
- sat: /^sobota/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "sl-SI",
- englishName: "Slovenian (Slovenia)",
- nativeName: "slovenski (Slovenija)",
-
- /* Day Name Strings */
- dayNames: ["nedelja", "ponedeljek", "torek", "sreda", "četrtek", "petek", "sobota"],
- abbreviatedDayNames: ["ned", "pon", "tor", "sre", "čet", "pet", "sob"],
- shortestDayNames: ["ne", "po", "to", "sr", "če", "pe", "so"],
- firstLetterDayNames: ["n", "p", "t", "s", "č", "p", "s"],
-
- /* Month Name Strings */
- monthNames: ["januar", "februar", "marec", "april", "maj", "junij", "julij", "avgust", "september", "oktober", "november", "december"],
- abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "avg", "sep", "okt", "nov", "dec"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "d.M.yyyy",
- longDate: "d. MMMM yyyy",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "d. MMMM yyyy H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "d. MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(uar)?/i,
- feb: /^feb(ruar)?/i,
- mar: /^mar(ec)?/i,
- apr: /^apr(il)?/i,
- may: /^maj/i,
- jun: /^jun(ij)?/i,
- jul: /^jul(ij)?/i,
- aug: /^avg(ust)?/i,
- sep: /^sep(t(ember)?)?/i,
- oct: /^okt(ober)?/i,
- nov: /^nov(ember)?/i,
- dec: /^dec(ember)?/i,
-
- sun: /^ne(d(elja)?)?/i,
- mon: /^po(n(edeljek)?)?/i,
- tue: /^to(r(ek)?)?/i,
- wed: /^sr(e(da)?)?/i,
- thu: /^če(t(rtek)?)?/i,
- fri: /^pe(t(ek)?)?/i,
- sat: /^so(b(ota)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "sv-SE",
- englishName: "Swedish (Sweden)",
- nativeName: "svenska (Sverige)",
-
- /* Day Name Strings */
- dayNames: ["söndag", "måndag", "tisdag", "onsdag", "torsdag", "fredag", "lördag"],
- abbreviatedDayNames: ["sö", "må", "ti", "on", "to", "fr", "lö"],
- shortestDayNames: ["sö", "må", "ti", "on", "to", "fr", "lö"],
- firstLetterDayNames: ["s", "m", "t", "o", "t", "f", "l"],
-
- /* Month Name Strings */
- monthNames: ["januari", "februari", "mars", "april", "maj", "juni", "juli", "augusti", "september", "oktober", "november", "december"],
- abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "ymd",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "yyyy-MM-dd",
- longDate: "'den 'd MMMM yyyy",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "'den 'd MMMM yyyy HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "'den 'd MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^jan(uari)?/i,
- feb: /^feb(ruari)?/i,
- mar: /^mar(s)?/i,
- apr: /^apr(il)?/i,
- may: /^maj/i,
- jun: /^jun(i)?/i,
- jul: /^jul(i)?/i,
- aug: /^aug(usti)?/i,
- sep: /^sep(t(ember)?)?/i,
- oct: /^okt(ober)?/i,
- nov: /^nov(ember)?/i,
- dec: /^dec(ember)?/i,
-
- sun: /^söndag/i,
- mon: /^måndag/i,
- tue: /^tisdag/i,
- wed: /^onsdag/i,
- thu: /^torsdag/i,
- fri: /^fredag/i,
- sat: /^lördag/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-function addTag(resource, type, endpoint)
-{
- if (!$('newtags-input_' + resource).value.blank()) {
- var params = new Object();
- params.imple="/action=add/resource=" + resource + "/type=" + type + "/tags=" + $('newtags-input_' + resource).value;
- new Ajax.Updater({success:'tags_' + resource},
- endpoint,
- {
- method: 'post',
- parameters: params,
- onComplete: function() {$('newtags-input_' + resource).value = "";}
- }
- );
- }
-
- return true;
-}
-
-function removeTag(resource, type, tagid, endpoint)
-{
- var params = new Object();
- params.imple = "/action=remove/resource=" + resource + "/type=" + type + "/tags=" + tagid;
- new Ajax.Updater({success:'tags_' + resource},
- endpoint,
- {
- method: 'post',
- parameters: params
- }
- );
-
- return true;
-}
+++ /dev/null
-/**
- * @version: 1.0 Alpha-1
- * @author: Coolite Inc. http://www.coolite.com/
- * @date: 2008-04-13
- * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
- * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
- * @website: http://www.datejs.com/
- */
-
-/*
- * TimeSpan(milliseconds);
- * TimeSpan(days, hours, minutes, seconds);
- * TimeSpan(days, hours, minutes, seconds, milliseconds);
- */
-var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
- var attrs = "days hours minutes seconds milliseconds".split(/\s+/);
-
- var gFn = function (attr) {
- return function () {
- return this[attr];
- };
- };
-
- var sFn = function (attr) {
- return function (val) {
- this[attr] = val;
- return this;
- };
- };
-
- for (var i = 0; i < attrs.length ; i++) {
- var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
- TimeSpan.prototype[$a] = 0;
- TimeSpan.prototype["get" + $b] = gFn($a);
- TimeSpan.prototype["set" + $b] = sFn($a);
- }
-
- if (arguments.length == 4) {
- this.setDays(days);
- this.setHours(hours);
- this.setMinutes(minutes);
- this.setSeconds(seconds);
- } else if (arguments.length == 5) {
- this.setDays(days);
- this.setHours(hours);
- this.setMinutes(minutes);
- this.setSeconds(seconds);
- this.setMilliseconds(milliseconds);
- } else if (arguments.length == 1 && typeof days == "number") {
- var orient = (days < 0) ? -1 : +1;
- this.setMilliseconds(Math.abs(days));
-
- this.setDays(Math.floor(this.getMilliseconds() / 86400000) * orient);
- this.setMilliseconds(this.getMilliseconds() % 86400000);
-
- this.setHours(Math.floor(this.getMilliseconds() / 3600000) * orient);
- this.setMilliseconds(this.getMilliseconds() % 3600000);
-
- this.setMinutes(Math.floor(this.getMilliseconds() / 60000) * orient);
- this.setMilliseconds(this.getMilliseconds() % 60000);
-
- this.setSeconds(Math.floor(this.getMilliseconds() / 1000) * orient);
- this.setMilliseconds(this.getMilliseconds() % 1000);
-
- this.setMilliseconds(this.getMilliseconds() * orient);
- }
-
- this.getTotalMilliseconds = function () {
- return (this.getDays() * 86400000) + (this.getHours() * 3600000) + (this.getMinutes() * 60000) + (this.getSeconds() * 1000);
- };
-
- this.compareTo = function (time) {
- var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
- if (time === null) {
- t2 = new Date(1970, 1, 1, 0, 0, 0);
- }
- else {
- t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
- }
- return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
- };
-
- this.equals = function (time) {
- return (this.compareTo(time) === 0);
- };
-
- this.add = function (time) {
- return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
- };
-
- this.subtract = function (time) {
- return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
- };
-
- this.addDays = function (n) {
- return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
- };
-
- this.addHours = function (n) {
- return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
- };
-
- this.addMinutes = function (n) {
- return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
- };
-
- this.addSeconds = function (n) {
- return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
- };
-
- this.addMilliseconds = function (n) {
- return new TimeSpan(this.getTotalMilliseconds() + n);
- };
-
- this.get12HourHour = function () {
- return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
- };
-
- this.getDesignator = function () {
- return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
- };
-
- this.toString = function (format) {
- this._toString = function () {
- if (this.getDays() !== null && this.getDays() > 0) {
- return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
- }
- else {
- return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
- }
- };
-
- this.p = function (s) {
- return (s.toString().length < 2) ? "0" + s : s;
- };
-
- var me = this;
-
- return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
- function (format) {
- switch (format) {
- case "d":
- return me.getDays();
- case "dd":
- return me.p(me.getDays());
- case "H":
- return me.getHours();
- case "HH":
- return me.p(me.getHours());
- case "h":
- return me.get12HourHour();
- case "hh":
- return me.p(me.get12HourHour());
- case "m":
- return me.getMinutes();
- case "mm":
- return me.p(me.getMinutes());
- case "s":
- return me.getSeconds();
- case "ss":
- return me.p(me.getSeconds());
- case "t":
- return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
- case "tt":
- return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
- }
- }
- ) : this._toString();
- };
- return this;
-};
-
-/**
- * Gets the time of day for this date instances.
- * @return {TimeSpan} TimeSpan
- */
-Date.prototype.getTimeOfDay = function () {
- return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
-};
-
-/*
- * TimePeriod(startDate, endDate);
- * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
- */
-var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
- var attrs = "years months days hours minutes seconds milliseconds".split(/\s+/);
-
- var gFn = function (attr) {
- return function () {
- return this[attr];
- };
- };
-
- var sFn = function (attr) {
- return function (val) {
- this[attr] = val;
- return this;
- };
- };
-
- for (var i = 0; i < attrs.length ; i++) {
- var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
- TimePeriod.prototype[$a] = 0;
- TimePeriod.prototype["get" + $b] = gFn($a);
- TimePeriod.prototype["set" + $b] = sFn($a);
- }
-
- if (arguments.length == 7) {
- this.years = years;
- this.months = months;
- this.setDays(days);
- this.setHours(hours);
- this.setMinutes(minutes);
- this.setSeconds(seconds);
- this.setMilliseconds(milliseconds);
- } else if (arguments.length == 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
- // startDate and endDate as arguments
-
- var d1 = years.clone();
- var d2 = months.clone();
-
- var temp = d1.clone();
- var orient = (d1 > d2) ? -1 : +1;
-
- this.years = d2.getFullYear() - d1.getFullYear();
- temp.addYears(this.years);
-
- if (orient == +1) {
- if (temp > d2) {
- if (this.years !== 0) {
- this.years--;
- }
- }
- } else {
- if (temp < d2) {
- if (this.years !== 0) {
- this.years++;
- }
- }
- }
-
- d1.addYears(this.years);
-
- if (orient == +1) {
- while (d1 < d2 && d1.clone().addDays(Date.getDaysInMonth(d1.getYear(), d1.getMonth()) ) < d2) {
- d1.addMonths(1);
- this.months++;
- }
- }
- else {
- while (d1 > d2 && d1.clone().addDays(-d1.getDaysInMonth()) > d2) {
- d1.addMonths(-1);
- this.months--;
- }
- }
-
- var diff = d2 - d1;
-
- if (diff !== 0) {
- var ts = new TimeSpan(diff);
- this.setDays(ts.getDays());
- this.setHours(ts.getHours());
- this.setMinutes(ts.getMinutes());
- this.setSeconds(ts.getSeconds());
- this.setMilliseconds(ts.getMilliseconds());
- }
- }
- return this;
-};
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "tr-TR",
- englishName: "Turkish (Turkey)",
- nativeName: "Türkçe (Türkiye)",
-
- /* Day Name Strings */
- dayNames: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"],
- abbreviatedDayNames: ["Paz", "Pzt", "Sal", "Çar", "Per", "Cum", "Cmt"],
- shortestDayNames: ["Pz", "Pt", "Sa", "Ça", "Pe", "Cu", "Ct"],
- firstLetterDayNames: ["P", "P", "S", "Ç", "P", "C", "C"],
-
- /* Month Name Strings */
- monthNames: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"],
- abbreviatedMonthNames: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd.MM.yyyy",
- longDate: "dd MMMM yyyy dddd",
- shortTime: "HH:mm",
- longTime: "HH:mm:ss",
- fullDateTime: "dd MMMM yyyy dddd HH:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "dd MMMM",
- yearMonth: "MMMM yyyy"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^oca(k)?/i,
- feb: /^şub(at)?/i,
- mar: /^mar(t)?/i,
- apr: /^nis(an)?/i,
- may: /^may(ıs)?/i,
- jun: /^haz(iran)?/i,
- jul: /^tem(muz)?/i,
- aug: /^ağu(stos)?/i,
- sep: /^eyl(ül)?/i,
- oct: /^eki(m)?/i,
- nov: /^kas(ım)?/i,
- dec: /^ara(lık)?/i,
-
- sun: /^pz(z(ar)?)?/i,
- mon: /^pt(t(artesi)?)?/i,
- tue: /^sa(l(ı)?)?/i,
- wed: /^ça(r(şamba)?)?/i,
- thu: /^pe(r(şembe)?)?/i,
- fri: /^cu(m(a)?)?/i,
- sat: /^ct(t(artesi)?)?/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "uk-UA",
- englishName: "Ukrainian (Ukraine)",
- nativeName: "україньска (Україна)",
-
- /* Day Name Strings */
- dayNames: ["неділя", "понеділок", "вівторок", "середа", "четвер", "п'ятниця", "субота"],
- abbreviatedDayNames: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
- shortestDayNames: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
- firstLetterDayNames: ["Н", "П", "В", "С", "Ч", "П", "С"],
-
- /* Month Name Strings */
- monthNames: ["Січень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"],
- abbreviatedMonthNames: ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру"],
-
- /* AM/PM Designators */
- amDesignator: "",
- pmDesignator: "",
-
- firstDayOfWeek: 1,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "dmy",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "dd.MM.yyyy",
- longDate: "d MMMM yyyy' р.'",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "d MMMM yyyy' р.' H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "d MMMM",
- yearMonth: "MMMM yyyy' р.'"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^січ(ень)?/i,
- feb: /^лют(ий)?/i,
- mar: /^бер(езень)?/i,
- apr: /^кві(тень)?/i,
- may: /^тра(вень)?/i,
- jun: /^чер(вень)?/i,
- jul: /^лип(ень)?/i,
- aug: /^сер(пень)?/i,
- sep: /^вер(есень)?/i,
- oct: /^жов(тень)?/i,
- nov: /^лис(топад)?/i,
- dec: /^гру(день)?/i,
-
- sun: /^неділя/i,
- mon: /^понеділок/i,
- tue: /^вівторок/i,
- wed: /^середа/i,
- thu: /^четвер/i,
- fri: /^п'ятниця/i,
- sat: /^субота/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-var eventTabs = null;
-var Views = {
-
- hash: $H(),
- keys: [],
-
- get: function(key)
- {
- return this.hash.get(key);
- },
-
- push: function(key, val)
- {
- this.hash.set(key, val);
- this.keys.push(key);
- if (this.hash.size() > 10) {
- this.hash.unset(this.keys.pop());
- }
- },
-
- invalidate: function()
- {
- this.hash = $H();
- this.keys = [];
- }
-
-};
-
-function ShowView(view, date, cache)
-{
- if (typeof Ajax.Updater == 'undefined') {
- return true;
- }
-
- if (Object.isUndefined(cache)) {
- cache = true;
- }
-
- // Build the request URL for later use, and as a hash key.
- var params = $H({ view: view });
- if (typeof date == 'object') {
- params.update(date);
- } else {
- params.set('date', date);
- }
-
- var url = KronolithVar.view_url + (KronolithVar.view_url.include('?') ? '&' : '?') + params.toQueryString();
-
- // Look for cached views.
- if (Views.get(url)) {
- $('page').update(Views.get(url));
- _ShowView();
- } else {
- // Add the Loading ... notice.
- $('page').appendChild(new Element('DIV', { id: 'pageLoading' }).update(KronolithText.loading));
- $('pageLoading').clonePosition('page');
- new Effect.Opacity('pageLoading', { from: 0.0, to: 0.5 });
-
- // Update the page div.
- if (cache) {
- new Ajax.Updater('page', url, { onComplete: function() { Views.push(url, $('page').innerHTML); _ShowView(); } });
- } else {
- new Ajax.Updater('page', url, { onComplete: _ShowView });
- }
- }
-
- return false;
-}
-
-function _ShowView()
-{
- if (Object.isFunction(stripeAllElements)) {
- stripeAllElements();
- }
- if (typeof Horde_ToolTips != 'undefined') {
- Horde_ToolTips.out();
- Horde_ToolTips.attachBehavior();
- }
-
- var titleDiv = $('view_title');
- if (titleDiv && titleDiv.firstChild && titleDiv.firstChild.nodeValue) {
- var title = KronolithVar.page_title + titleDiv.firstChild.nodeValue;
- try {
- document.title = title;
- if (parent.frames.horde_main) {
- parent.document.title = title;
- }
- } catch (e) {}
- }
-
- var viewVars = $('view_vars');
- if (viewVars) {
- kronolithView = viewVars.readAttribute('view');
- kronolithDate = new Date(viewVars.readAttribute('date'));
- kronolithPrintLink = viewVars.readAttribute('print');
- }
-}
-
-function ShowTab(tab)
-{
- if (eventTabs == null) {
- eventTabs = $('page').select('.tabset ul li');
- }
-
- eventTabs.each(function(c) {
- var t = $(c.id.substring(3));
- if (!t) {
- return;
- }
- if (c.id == 'tab' + tab) {
- c.addClassName('activeTab');
- t.show();
- } else {
- c.removeClassName('activeTab');
- t.hide();
- }
- });
-
- return false;
-}
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "zh-CN",
- englishName: "Chinese (People's Republic of China)",
- nativeName: "中文(中华人民共和国)",
-
- /* Day Name Strings */
- dayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
- abbreviatedDayNames: ["日", "一", "二", "三", "四", "五", "六"],
- shortestDayNames: ["日", "一", "二", "三", "四", "五", "六"],
- firstLetterDayNames: ["日", "一", "二", "三", "四", "五", "六"],
-
- /* Month Name Strings */
- monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
- abbreviatedMonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
-
- /* AM/PM Designators */
- amDesignator: "上午",
- pmDesignator: "下午",
-
- firstDayOfWeek: 0,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "ymd",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "yyyy/M/d",
- longDate: "yyyy'年'M'月'd'日'",
- shortTime: "H:mm",
- longTime: "H:mm:ss",
- fullDateTime: "yyyy'年'M'月'd'日' H:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "M'月'd'日'",
- yearMonth: "yyyy'年'M'月'"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^一月/i,
- feb: /^二月/i,
- mar: /^三月/i,
- apr: /^四月/i,
- may: /^五月/i,
- jun: /^六月/i,
- jul: /^七月/i,
- aug: /^八月/i,
- sep: /^九月/i,
- oct: /^十月/i,
- nov: /^十一月/i,
- dec: /^十二月/i,
-
- sun: /^星期日/i,
- mon: /^星期一/i,
- tue: /^星期二/i,
- wed: /^星期三/i,
- thu: /^星期四/i,
- fri: /^星期五/i,
- sat: /^星期六/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
+++ /dev/null
-Date.CultureInfo = {
- /* Culture Name */
- name: "zh-TW",
- englishName: "Chinese (Taiwan)",
- nativeName: "中文(台灣)",
-
- /* Day Name Strings */
- dayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
- abbreviatedDayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
- shortestDayNames: ["日", "一", "二", "三", "四", "五", "六"],
- firstLetterDayNames: ["日", "一", "二", "三", "四", "五", "六"],
-
- /* Month Name Strings */
- monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
- abbreviatedMonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
-
- /* AM/PM Designators */
- amDesignator: "上午",
- pmDesignator: "下午",
-
- firstDayOfWeek: 0,
- twoDigitYearMax: 2029,
-
- /**
- * The dateElementOrder is based on the order of the
- * format specifiers in the formatPatterns.DatePattern.
- *
- * Example:
- <pre>
- shortDatePattern dateElementOrder
- ------------------ ----------------
- "M/d/yyyy" "mdy"
- "dd/MM/yyyy" "dmy"
- "yyyy-MM-dd" "ymd"
- </pre>
- *
- * The correct dateElementOrder is required by the parser to
- * determine the expected order of the date elements in the
- * string being parsed.
- */
- dateElementOrder: "ymd",
-
- /* Standard date and time format patterns */
- formatPatterns: {
- shortDate: "yyyy/M/d",
- longDate: "yyyy'年'M'月'd'日'",
- shortTime: "tt hh:mm",
- longTime: "tt hh:mm:ss",
- fullDateTime: "yyyy'年'M'月'd'日' tt hh:mm:ss",
- sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
- universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
- rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
- monthDay: "M'月'd'日'",
- yearMonth: "yyyy'年'M'月'"
- },
-
- /**
- * NOTE: If a string format is not parsing correctly, but
- * you would expect it parse, the problem likely lies below.
- *
- * The following regex patterns control most of the string matching
- * within the parser.
- *
- * The Month name and Day name patterns were automatically generated
- * and in general should be (mostly) correct.
- *
- * Beyond the month and day name patterns are natural language strings.
- * Example: "next", "today", "months"
- *
- * These natural language string may NOT be correct for this culture.
- * If they are not correct, please translate and edit this file
- * providing the correct regular expression pattern.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
- *
- * We will add the modified patterns to the master source files.
- *
- * As well, please review the list of "Future Strings" section below.
- */
- regexPatterns: {
- jan: /^一月/i,
- feb: /^二月/i,
- mar: /^三月/i,
- apr: /^四月/i,
- may: /^五月/i,
- jun: /^六月/i,
- jul: /^七月/i,
- aug: /^八月/i,
- sep: /^九月/i,
- oct: /^十月/i,
- nov: /^十一月/i,
- dec: /^十二月/i,
-
- sun: /^星期日/i,
- mon: /^星期一/i,
- tue: /^星期二/i,
- wed: /^星期三/i,
- thu: /^星期四/i,
- fri: /^星期五/i,
- sat: /^星期六/i,
-
- future: /^next/i,
- past: /^last|past|prev(ious)?/i,
- add: /^(\+|aft(er)?|from|hence)/i,
- subtract: /^(\-|bef(ore)?|ago)/i,
-
- yesterday: /^yes(terday)?/i,
- today: /^t(od(ay)?)?/i,
- tomorrow: /^tom(orrow)?/i,
- now: /^n(ow)?/i,
-
- millisecond: /^ms|milli(second)?s?/i,
- second: /^sec(ond)?s?/i,
- minute: /^mn|min(ute)?s?/i,
- hour: /^h(our)?s?/i,
- week: /^w(eek)?s?/i,
- month: /^m(onth)?s?/i,
- day: /^d(ay)?s?/i,
- year: /^y(ear)?s?/i,
-
- shortMeridian: /^(a|p)/i,
- longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
- timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
- ordinalSuffix: /^\s*(st|nd|rd|th)/i,
- timeContext: /^\s*(\:|a(?!u|p)|p)/i
- },
-
- timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
-};
-
-/********************
- ** Future Strings **
- ********************
- *
- * The following list of strings may not be currently being used, but
- * may be incorporated into the Datejs library later.
- *
- * We would appreciate any help translating the strings below.
- *
- * If you modify this file, please post your revised CultureInfo file
- * to the Datejs Forum located at http://www.datejs.com/forums/.
- *
- * Please mark the subject of the post with [CultureInfo]. Example:
- * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
- *
- * English Name Translated
- * ------------------ -----------------
- * about about
- * ago ago
- * date date
- * time time
- * calendar calendar
- * show show
- * hourly hourly
- * daily daily
- * weekly weekly
- * bi-weekly bi-weekly
- * fortnight fortnight
- * monthly monthly
- * bi-monthly bi-monthly
- * quarter quarter
- * quarterly quarterly
- * yearly yearly
- * annual annual
- * annually annually
- * annum annum
- * again again
- * between between
- * after after
- * from now from now
- * repeat repeat
- * times times
- * per per
- * min (abbrev minute) min
- * morning morning
- * noon noon
- * night night
- * midnight midnight
- * mid-night mid-night
- * evening evening
- * final final
- * future future
- * spring spring
- * summer summer
- * fall fall
- * winter winter
- * end of end of
- * end end
- * long long
- * short short
- */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "sv-SE",
+ englishName: "Swedish (Sweden)",
+ nativeName: "svenska (Sverige)",
+
+ /* Day Name Strings */
+ dayNames: ["söndag", "måndag", "tisdag", "onsdag", "torsdag", "fredag", "lördag"],
+ abbreviatedDayNames: ["sö", "må", "ti", "on", "to", "fr", "lö"],
+ shortestDayNames: ["sö", "må", "ti", "on", "to", "fr", "lö"],
+ firstLetterDayNames: ["s", "m", "t", "o", "t", "f", "l"],
+
+ /* Month Name Strings */
+ monthNames: ["januari", "februari", "mars", "april", "maj", "juni", "juli", "augusti", "september", "oktober", "november", "december"],
+ abbreviatedMonthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug", "sep", "okt", "nov", "dec"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy-MM-dd",
+ longDate: "'den 'd MMMM yyyy",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "'den 'd MMMM yyyy HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "'den 'd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^jan(uari)?/i,
+ feb: /^feb(ruari)?/i,
+ mar: /^mar(s)?/i,
+ apr: /^apr(il)?/i,
+ may: /^maj/i,
+ jun: /^jun(i)?/i,
+ jul: /^jul(i)?/i,
+ aug: /^aug(usti)?/i,
+ sep: /^sep(t(ember)?)?/i,
+ oct: /^okt(ober)?/i,
+ nov: /^nov(ember)?/i,
+ dec: /^dec(ember)?/i,
+
+ sun: /^söndag/i,
+ mon: /^måndag/i,
+ tue: /^tisdag/i,
+ wed: /^onsdag/i,
+ thu: /^torsdag/i,
+ fri: /^fredag/i,
+ sat: /^lördag/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+function addTag(resource, type, endpoint)
+{
+ if (!$('newtags-input_' + resource).value.blank()) {
+ var params = new Object();
+ params.imple="/action=add/resource=" + resource + "/type=" + type + "/tags=" + $('newtags-input_' + resource).value;
+ new Ajax.Updater({success:'tags_' + resource},
+ endpoint,
+ {
+ method: 'post',
+ parameters: params,
+ onComplete: function() {$('newtags-input_' + resource).value = "";}
+ }
+ );
+ }
+
+ return true;
+}
+
+function removeTag(resource, type, tagid, endpoint)
+{
+ var params = new Object();
+ params.imple = "/action=remove/resource=" + resource + "/type=" + type + "/tags=" + tagid;
+ new Ajax.Updater({success:'tags_' + resource},
+ endpoint,
+ {
+ method: 'post',
+ parameters: params
+ }
+ );
+
+ return true;
+}
--- /dev/null
+/**
+ * @version: 1.0 Alpha-1
+ * @author: Coolite Inc. http://www.coolite.com/
+ * @date: 2008-04-13
+ * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
+ * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
+ * @website: http://www.datejs.com/
+ */
+
+/*
+ * TimeSpan(milliseconds);
+ * TimeSpan(days, hours, minutes, seconds);
+ * TimeSpan(days, hours, minutes, seconds, milliseconds);
+ */
+var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
+ var attrs = "days hours minutes seconds milliseconds".split(/\s+/);
+
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ TimeSpan.prototype[$a] = 0;
+ TimeSpan.prototype["get" + $b] = gFn($a);
+ TimeSpan.prototype["set" + $b] = sFn($a);
+ }
+
+ if (arguments.length == 4) {
+ this.setDays(days);
+ this.setHours(hours);
+ this.setMinutes(minutes);
+ this.setSeconds(seconds);
+ } else if (arguments.length == 5) {
+ this.setDays(days);
+ this.setHours(hours);
+ this.setMinutes(minutes);
+ this.setSeconds(seconds);
+ this.setMilliseconds(milliseconds);
+ } else if (arguments.length == 1 && typeof days == "number") {
+ var orient = (days < 0) ? -1 : +1;
+ this.setMilliseconds(Math.abs(days));
+
+ this.setDays(Math.floor(this.getMilliseconds() / 86400000) * orient);
+ this.setMilliseconds(this.getMilliseconds() % 86400000);
+
+ this.setHours(Math.floor(this.getMilliseconds() / 3600000) * orient);
+ this.setMilliseconds(this.getMilliseconds() % 3600000);
+
+ this.setMinutes(Math.floor(this.getMilliseconds() / 60000) * orient);
+ this.setMilliseconds(this.getMilliseconds() % 60000);
+
+ this.setSeconds(Math.floor(this.getMilliseconds() / 1000) * orient);
+ this.setMilliseconds(this.getMilliseconds() % 1000);
+
+ this.setMilliseconds(this.getMilliseconds() * orient);
+ }
+
+ this.getTotalMilliseconds = function () {
+ return (this.getDays() * 86400000) + (this.getHours() * 3600000) + (this.getMinutes() * 60000) + (this.getSeconds() * 1000);
+ };
+
+ this.compareTo = function (time) {
+ var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
+ if (time === null) {
+ t2 = new Date(1970, 1, 1, 0, 0, 0);
+ }
+ else {
+ t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
+ }
+ return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
+ };
+
+ this.equals = function (time) {
+ return (this.compareTo(time) === 0);
+ };
+
+ this.add = function (time) {
+ return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
+ };
+
+ this.subtract = function (time) {
+ return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
+ };
+
+ this.addDays = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
+ };
+
+ this.addHours = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
+ };
+
+ this.addMinutes = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
+ };
+
+ this.addSeconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
+ };
+
+ this.addMilliseconds = function (n) {
+ return new TimeSpan(this.getTotalMilliseconds() + n);
+ };
+
+ this.get12HourHour = function () {
+ return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
+ };
+
+ this.getDesignator = function () {
+ return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ };
+
+ this.toString = function (format) {
+ this._toString = function () {
+ if (this.getDays() !== null && this.getDays() > 0) {
+ return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ else {
+ return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
+ }
+ };
+
+ this.p = function (s) {
+ return (s.toString().length < 2) ? "0" + s : s;
+ };
+
+ var me = this;
+
+ return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
+ function (format) {
+ switch (format) {
+ case "d":
+ return me.getDays();
+ case "dd":
+ return me.p(me.getDays());
+ case "H":
+ return me.getHours();
+ case "HH":
+ return me.p(me.getHours());
+ case "h":
+ return me.get12HourHour();
+ case "hh":
+ return me.p(me.get12HourHour());
+ case "m":
+ return me.getMinutes();
+ case "mm":
+ return me.p(me.getMinutes());
+ case "s":
+ return me.getSeconds();
+ case "ss":
+ return me.p(me.getSeconds());
+ case "t":
+ return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
+ case "tt":
+ return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
+ }
+ }
+ ) : this._toString();
+ };
+ return this;
+};
+
+/**
+ * Gets the time of day for this date instances.
+ * @return {TimeSpan} TimeSpan
+ */
+Date.prototype.getTimeOfDay = function () {
+ return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
+};
+
+/*
+ * TimePeriod(startDate, endDate);
+ * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
+ */
+var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
+ var attrs = "years months days hours minutes seconds milliseconds".split(/\s+/);
+
+ var gFn = function (attr) {
+ return function () {
+ return this[attr];
+ };
+ };
+
+ var sFn = function (attr) {
+ return function (val) {
+ this[attr] = val;
+ return this;
+ };
+ };
+
+ for (var i = 0; i < attrs.length ; i++) {
+ var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
+ TimePeriod.prototype[$a] = 0;
+ TimePeriod.prototype["get" + $b] = gFn($a);
+ TimePeriod.prototype["set" + $b] = sFn($a);
+ }
+
+ if (arguments.length == 7) {
+ this.years = years;
+ this.months = months;
+ this.setDays(days);
+ this.setHours(hours);
+ this.setMinutes(minutes);
+ this.setSeconds(seconds);
+ this.setMilliseconds(milliseconds);
+ } else if (arguments.length == 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
+ // startDate and endDate as arguments
+
+ var d1 = years.clone();
+ var d2 = months.clone();
+
+ var temp = d1.clone();
+ var orient = (d1 > d2) ? -1 : +1;
+
+ this.years = d2.getFullYear() - d1.getFullYear();
+ temp.addYears(this.years);
+
+ if (orient == +1) {
+ if (temp > d2) {
+ if (this.years !== 0) {
+ this.years--;
+ }
+ }
+ } else {
+ if (temp < d2) {
+ if (this.years !== 0) {
+ this.years++;
+ }
+ }
+ }
+
+ d1.addYears(this.years);
+
+ if (orient == +1) {
+ while (d1 < d2 && d1.clone().addDays(Date.getDaysInMonth(d1.getYear(), d1.getMonth()) ) < d2) {
+ d1.addMonths(1);
+ this.months++;
+ }
+ }
+ else {
+ while (d1 > d2 && d1.clone().addDays(-d1.getDaysInMonth()) > d2) {
+ d1.addMonths(-1);
+ this.months--;
+ }
+ }
+
+ var diff = d2 - d1;
+
+ if (diff !== 0) {
+ var ts = new TimeSpan(diff);
+ this.setDays(ts.getDays());
+ this.setHours(ts.getHours());
+ this.setMinutes(ts.getMinutes());
+ this.setSeconds(ts.getSeconds());
+ this.setMilliseconds(ts.getMilliseconds());
+ }
+ }
+ return this;
+};
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "tr-TR",
+ englishName: "Turkish (Turkey)",
+ nativeName: "Türkçe (Türkiye)",
+
+ /* Day Name Strings */
+ dayNames: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"],
+ abbreviatedDayNames: ["Paz", "Pzt", "Sal", "Çar", "Per", "Cum", "Cmt"],
+ shortestDayNames: ["Pz", "Pt", "Sa", "Ça", "Pe", "Cu", "Ct"],
+ firstLetterDayNames: ["P", "P", "S", "Ç", "P", "C", "C"],
+
+ /* Month Name Strings */
+ monthNames: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"],
+ abbreviatedMonthNames: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "dd MMMM yyyy dddd",
+ shortTime: "HH:mm",
+ longTime: "HH:mm:ss",
+ fullDateTime: "dd MMMM yyyy dddd HH:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "dd MMMM",
+ yearMonth: "MMMM yyyy"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^oca(k)?/i,
+ feb: /^şub(at)?/i,
+ mar: /^mar(t)?/i,
+ apr: /^nis(an)?/i,
+ may: /^may(ıs)?/i,
+ jun: /^haz(iran)?/i,
+ jul: /^tem(muz)?/i,
+ aug: /^ağu(stos)?/i,
+ sep: /^eyl(ül)?/i,
+ oct: /^eki(m)?/i,
+ nov: /^kas(ım)?/i,
+ dec: /^ara(lık)?/i,
+
+ sun: /^pz(z(ar)?)?/i,
+ mon: /^pt(t(artesi)?)?/i,
+ tue: /^sa(l(ı)?)?/i,
+ wed: /^ça(r(şamba)?)?/i,
+ thu: /^pe(r(şembe)?)?/i,
+ fri: /^cu(m(a)?)?/i,
+ sat: /^ct(t(artesi)?)?/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "uk-UA",
+ englishName: "Ukrainian (Ukraine)",
+ nativeName: "україньска (Україна)",
+
+ /* Day Name Strings */
+ dayNames: ["неділя", "понеділок", "вівторок", "середа", "четвер", "п'ятниця", "субота"],
+ abbreviatedDayNames: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
+ shortestDayNames: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
+ firstLetterDayNames: ["Н", "П", "В", "С", "Ч", "П", "С"],
+
+ /* Month Name Strings */
+ monthNames: ["Січень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"],
+ abbreviatedMonthNames: ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру"],
+
+ /* AM/PM Designators */
+ amDesignator: "",
+ pmDesignator: "",
+
+ firstDayOfWeek: 1,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "dmy",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "dd.MM.yyyy",
+ longDate: "d MMMM yyyy' р.'",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "d MMMM yyyy' р.' H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "d MMMM",
+ yearMonth: "MMMM yyyy' р.'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^січ(ень)?/i,
+ feb: /^лют(ий)?/i,
+ mar: /^бер(езень)?/i,
+ apr: /^кві(тень)?/i,
+ may: /^тра(вень)?/i,
+ jun: /^чер(вень)?/i,
+ jul: /^лип(ень)?/i,
+ aug: /^сер(пень)?/i,
+ sep: /^вер(есень)?/i,
+ oct: /^жов(тень)?/i,
+ nov: /^лис(топад)?/i,
+ dec: /^гру(день)?/i,
+
+ sun: /^неділя/i,
+ mon: /^понеділок/i,
+ tue: /^вівторок/i,
+ wed: /^середа/i,
+ thu: /^четвер/i,
+ fri: /^п'ятниця/i,
+ sat: /^субота/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+var eventTabs = null;
+var Views = {
+
+ hash: $H(),
+ keys: [],
+
+ get: function(key)
+ {
+ return this.hash.get(key);
+ },
+
+ push: function(key, val)
+ {
+ this.hash.set(key, val);
+ this.keys.push(key);
+ if (this.hash.size() > 10) {
+ this.hash.unset(this.keys.pop());
+ }
+ },
+
+ invalidate: function()
+ {
+ this.hash = $H();
+ this.keys = [];
+ }
+
+};
+
+function ShowView(view, date, cache)
+{
+ if (typeof Ajax.Updater == 'undefined') {
+ return true;
+ }
+
+ if (Object.isUndefined(cache)) {
+ cache = true;
+ }
+
+ // Build the request URL for later use, and as a hash key.
+ var params = $H({ view: view });
+ if (typeof date == 'object') {
+ params.update(date);
+ } else {
+ params.set('date', date);
+ }
+
+ var url = KronolithVar.view_url + (KronolithVar.view_url.include('?') ? '&' : '?') + params.toQueryString();
+
+ // Look for cached views.
+ if (Views.get(url)) {
+ $('page').update(Views.get(url));
+ _ShowView();
+ } else {
+ // Add the Loading ... notice.
+ $('page').appendChild(new Element('DIV', { id: 'pageLoading' }).update(KronolithText.loading));
+ $('pageLoading').clonePosition('page');
+ new Effect.Opacity('pageLoading', { from: 0.0, to: 0.5 });
+
+ // Update the page div.
+ if (cache) {
+ new Ajax.Updater('page', url, { onComplete: function() { Views.push(url, $('page').innerHTML); _ShowView(); } });
+ } else {
+ new Ajax.Updater('page', url, { onComplete: _ShowView });
+ }
+ }
+
+ return false;
+}
+
+function _ShowView()
+{
+ if (Object.isFunction(stripeAllElements)) {
+ stripeAllElements();
+ }
+ if (typeof Horde_ToolTips != 'undefined') {
+ Horde_ToolTips.out();
+ Horde_ToolTips.attachBehavior();
+ }
+
+ var titleDiv = $('view_title');
+ if (titleDiv && titleDiv.firstChild && titleDiv.firstChild.nodeValue) {
+ var title = KronolithVar.page_title + titleDiv.firstChild.nodeValue;
+ try {
+ document.title = title;
+ if (parent.frames.horde_main) {
+ parent.document.title = title;
+ }
+ } catch (e) {}
+ }
+
+ var viewVars = $('view_vars');
+ if (viewVars) {
+ kronolithView = viewVars.readAttribute('view');
+ kronolithDate = new Date(viewVars.readAttribute('date'));
+ kronolithPrintLink = viewVars.readAttribute('print');
+ }
+}
+
+function ShowTab(tab)
+{
+ if (eventTabs == null) {
+ eventTabs = $('page').select('.tabset ul li');
+ }
+
+ eventTabs.each(function(c) {
+ var t = $(c.id.substring(3));
+ if (!t) {
+ return;
+ }
+ if (c.id == 'tab' + tab) {
+ c.addClassName('activeTab');
+ t.show();
+ } else {
+ c.removeClassName('activeTab');
+ t.hide();
+ }
+ });
+
+ return false;
+}
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "zh-CN",
+ englishName: "Chinese (People's Republic of China)",
+ nativeName: "中文(中华人民共和国)",
+
+ /* Day Name Strings */
+ dayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
+ abbreviatedDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+ shortestDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+ firstLetterDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+
+ /* Month Name Strings */
+ monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
+ abbreviatedMonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
+
+ /* AM/PM Designators */
+ amDesignator: "上午",
+ pmDesignator: "下午",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/M/d",
+ longDate: "yyyy'年'M'月'd'日'",
+ shortTime: "H:mm",
+ longTime: "H:mm:ss",
+ fullDateTime: "yyyy'年'M'月'd'日' H:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "M'月'd'日'",
+ yearMonth: "yyyy'年'M'月'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^一月/i,
+ feb: /^二月/i,
+ mar: /^三月/i,
+ apr: /^四月/i,
+ may: /^五月/i,
+ jun: /^六月/i,
+ jul: /^七月/i,
+ aug: /^八月/i,
+ sep: /^九月/i,
+ oct: /^十月/i,
+ nov: /^十一月/i,
+ dec: /^十二月/i,
+
+ sun: /^星期日/i,
+ mon: /^星期一/i,
+ tue: /^星期二/i,
+ wed: /^星期三/i,
+ thu: /^星期四/i,
+ fri: /^星期五/i,
+ sat: /^星期六/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+Date.CultureInfo = {
+ /* Culture Name */
+ name: "zh-TW",
+ englishName: "Chinese (Taiwan)",
+ nativeName: "中文(台灣)",
+
+ /* Day Name Strings */
+ dayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
+ abbreviatedDayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
+ shortestDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+ firstLetterDayNames: ["日", "一", "二", "三", "四", "五", "六"],
+
+ /* Month Name Strings */
+ monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
+ abbreviatedMonthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
+
+ /* AM/PM Designators */
+ amDesignator: "上午",
+ pmDesignator: "下午",
+
+ firstDayOfWeek: 0,
+ twoDigitYearMax: 2029,
+
+ /**
+ * The dateElementOrder is based on the order of the
+ * format specifiers in the formatPatterns.DatePattern.
+ *
+ * Example:
+ <pre>
+ shortDatePattern dateElementOrder
+ ------------------ ----------------
+ "M/d/yyyy" "mdy"
+ "dd/MM/yyyy" "dmy"
+ "yyyy-MM-dd" "ymd"
+ </pre>
+ *
+ * The correct dateElementOrder is required by the parser to
+ * determine the expected order of the date elements in the
+ * string being parsed.
+ */
+ dateElementOrder: "ymd",
+
+ /* Standard date and time format patterns */
+ formatPatterns: {
+ shortDate: "yyyy/M/d",
+ longDate: "yyyy'年'M'月'd'日'",
+ shortTime: "tt hh:mm",
+ longTime: "tt hh:mm:ss",
+ fullDateTime: "yyyy'年'M'月'd'日' tt hh:mm:ss",
+ sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
+ universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
+ rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
+ monthDay: "M'月'd'日'",
+ yearMonth: "yyyy'年'M'月'"
+ },
+
+ /**
+ * NOTE: If a string format is not parsing correctly, but
+ * you would expect it parse, the problem likely lies below.
+ *
+ * The following regex patterns control most of the string matching
+ * within the parser.
+ *
+ * The Month name and Day name patterns were automatically generated
+ * and in general should be (mostly) correct.
+ *
+ * Beyond the month and day name patterns are natural language strings.
+ * Example: "next", "today", "months"
+ *
+ * These natural language string may NOT be correct for this culture.
+ * If they are not correct, please translate and edit this file
+ * providing the correct regular expression pattern.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
+ *
+ * We will add the modified patterns to the master source files.
+ *
+ * As well, please review the list of "Future Strings" section below.
+ */
+ regexPatterns: {
+ jan: /^一月/i,
+ feb: /^二月/i,
+ mar: /^三月/i,
+ apr: /^四月/i,
+ may: /^五月/i,
+ jun: /^六月/i,
+ jul: /^七月/i,
+ aug: /^八月/i,
+ sep: /^九月/i,
+ oct: /^十月/i,
+ nov: /^十一月/i,
+ dec: /^十二月/i,
+
+ sun: /^星期日/i,
+ mon: /^星期一/i,
+ tue: /^星期二/i,
+ wed: /^星期三/i,
+ thu: /^星期四/i,
+ fri: /^星期五/i,
+ sat: /^星期六/i,
+
+ future: /^next/i,
+ past: /^last|past|prev(ious)?/i,
+ add: /^(\+|aft(er)?|from|hence)/i,
+ subtract: /^(\-|bef(ore)?|ago)/i,
+
+ yesterday: /^yes(terday)?/i,
+ today: /^t(od(ay)?)?/i,
+ tomorrow: /^tom(orrow)?/i,
+ now: /^n(ow)?/i,
+
+ millisecond: /^ms|milli(second)?s?/i,
+ second: /^sec(ond)?s?/i,
+ minute: /^mn|min(ute)?s?/i,
+ hour: /^h(our)?s?/i,
+ week: /^w(eek)?s?/i,
+ month: /^m(onth)?s?/i,
+ day: /^d(ay)?s?/i,
+ year: /^y(ear)?s?/i,
+
+ shortMeridian: /^(a|p)/i,
+ longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
+ timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,
+ ordinalSuffix: /^\s*(st|nd|rd|th)/i,
+ timeContext: /^\s*(\:|a(?!u|p)|p)/i
+ },
+
+ timezones: [{name:"UTC", offset:"-000"}, {name:"GMT", offset:"-000"}, {name:"EST", offset:"-0500"}, {name:"EDT", offset:"-0400"}, {name:"CST", offset:"-0600"}, {name:"CDT", offset:"-0500"}, {name:"MST", offset:"-0700"}, {name:"MDT", offset:"-0600"}, {name:"PST", offset:"-0800"}, {name:"PDT", offset:"-0700"}]
+};
+
+/********************
+ ** Future Strings **
+ ********************
+ *
+ * The following list of strings may not be currently being used, but
+ * may be incorporated into the Datejs library later.
+ *
+ * We would appreciate any help translating the strings below.
+ *
+ * If you modify this file, please post your revised CultureInfo file
+ * to the Datejs Forum located at http://www.datejs.com/forums/.
+ *
+ * Please mark the subject of the post with [CultureInfo]. Example:
+ * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)b
+ *
+ * English Name Translated
+ * ------------------ -----------------
+ * about about
+ * ago ago
+ * date date
+ * time time
+ * calendar calendar
+ * show show
+ * hourly hourly
+ * daily daily
+ * weekly weekly
+ * bi-weekly bi-weekly
+ * fortnight fortnight
+ * monthly monthly
+ * bi-monthly bi-monthly
+ * quarter quarter
+ * quarterly quarterly
+ * yearly yearly
+ * annual annual
+ * annually annually
+ * annum annum
+ * again again
+ * between between
+ * after after
+ * from now from now
+ * repeat repeat
+ * times times
+ * per per
+ * min (abbrev minute) min
+ * morning morning
+ * noon noon
+ * night night
+ * midnight midnight
+ * mid-night mid-night
+ * evening evening
+ * final final
+ * future future
+ * spring spring
+ * summer summer
+ * fall fall
+ * winter winter
+ * end of end of
+ * end end
+ * long long
+ * short short
+ */
--- /dev/null
+/**
+ * Update news source feed
+ *
+ * $Id:$
+ */
+function getFeed() {
+
+ RedBox.loading();
+
+ new Ajax.Updater('feed_content',
+ document.feed_select.action,
+ {
+ onComplete: function() {
+ RedBox.close();
+ },
+ parameters: {
+ feed_id: $F('feed_id')
+ },
+ onFailure: function() {
+ RedBox.close();
+ alert('Error');
+ },
+ asynchronous: true
+ });
+}
+++ /dev/null
-/**
- * Update news source feed
- *
- * $Id:$
- */
-function getFeed() {
-
- RedBox.loading();
-
- new Ajax.Updater('feed_content',
- document.feed_select.action,
- {
- onComplete: function() {
- RedBox.close();
- },
- parameters: {
- feed_id: $F('feed_id')
- },
- onFailure: function() {
- RedBox.close();
- alert('Error');
- },
- asynchronous: true
- });
-}
+++ /dev/null
-var contactTabs = null;
-function ShowTab(tab)
-{
- if (contactTabs == null) {
- contactTabs = $('page').select('.tabset')[0].down();
- }
-
- contactTabs.select('li').each(function(item) {
- if (item.id == 'tab' + tab) {
- item.addClassName('activeTab');
- $(item.id.substring(3)).show();
- } else {
- item.removeClassName('activeTab');
- $(item.id.substring(3)).hide();
- }
- });
-
- return false;
-}