Editorial Calendar - Version 1.3

Version Description

  • The Editorial Calendar will now show up for each custom post type and support a separate calendar for each type.
  • We are now disabling the save button on the quick edit dialog after it is pressed and before the post saves to prevent duplicate posts if the user presses the button twice in a row.
  • Upgraded the to the latest version of QUnit for our unit test framework
  • The calendar now supports Brazilian Portuguese. Thanks to Janio Sarmento who uses the Editorial Calendar on his site O Blogue do Janio.
Download this release

Release Info

Developer zgrossbart
Plugin Icon wp plugin Editorial Calendar
Version 1.3
Comparing to
See all releases

Code changes from version 1.2 to 1.3

closure.sh CHANGED
@@ -1,3 +1,3 @@
1
- java -jar closure/compiler.jar --js_output_file lib/edcallib.min.js --js lib/humanmsg.js --js lib/jquery.cookie.js --js lib/jquery.bgiframe.js --js lib/jquery.delegate.js --js lib/jquery.tools.min.js --js lib/jquery.timepicker.js --js lib/json2.js --js lib/tools.scrollable-1.1.2.js --js lib/tools.scrollable.mousewheel-1.0.1.js --js lib/ui.core.js --js lib/ui.draggable.js --js lib/ui.droppable.js --js lib/date.extras.js
2
 
3
  java -jar closure/compiler.jar --js_output_file edcal.min.js --js edcal.js
1
+ java -jar closure/compiler.jar --js_output_file lib/edcallib.min.js --js lib/humanmsg.js --js lib/sprintf-0.7-beta1.js --js lib/jquery.cookie.js --js lib/jquery.bgiframe.js --js lib/jquery.delegate.js --js lib/jquery.tools.min.js --js lib/jquery.timepicker.js --js lib/json2.js --js lib/tools.scrollable-1.1.2.js --js lib/tools.scrollable.mousewheel-1.0.1.js --js lib/ui.core.js --js lib/ui.draggable.js --js lib/ui.droppable.js --js lib/date.extras.js
2
 
3
  java -jar closure/compiler.jar --js_output_file edcal.min.js --js edcal.js
edcal.js CHANGED
@@ -13,7 +13,7 @@
13
  * limitations under the License.
14
  *
15
  ******************************************************************************/
16
-
17
  /*
18
  This is the WordPress editorial calendar. It is a continuous
19
  calendar in both directions. That means instead of showing only
@@ -21,10 +21,10 @@
21
  can scroll from one month to the next using the up and down
22
  arrow keys, the page up and page down keys, the next and previous
23
  month buttons, and their mouse wheel.
24
-
25
  The calendar shows five weeks visible at a time and maintains 11
26
  weeks of rendered HTML. Only the middle weeks are visible.
27
-
28
  Week 1
29
  Week 2
30
  Week 3
@@ -36,17 +36,17 @@
36
  Week 9
37
  Week 10
38
  Week 11
39
-
40
  When the user scrolls down one week the new week is added at the
41
  end of the calendar and the first week is removed. In this way
42
  the calendar will only ever have 11 weeks total and won't use up
43
  excessive memory.
44
-
45
  This calendar uses AJAX to call into the functions defined in
46
  edcal.php. These functions get posts and change post dates.
47
-
48
  The HTML structure of the calendar is:
49
-
50
  <div id="cal">
51
  <div id="row08Nov2009">
52
  <div id="row08Nov2009row">
@@ -62,13 +62,13 @@
62
  </div>
63
  */
64
  var edcal = {
65
-
66
  /*
67
  This value is the number of weeks the user wants to see at one time
68
  in the calendar.
69
  */
70
  weeksPref: 3,
71
-
72
  /*
73
  This is a preference value indicating if you see the post status
74
  */
@@ -88,7 +88,7 @@ var edcal = {
88
  This is a preference value indicating if we should prompt for feeback
89
  */
90
  doFeedbackPref: true,
91
-
92
  /*
93
  * True if the calendar is in the process of moving
94
  */
@@ -98,7 +98,7 @@ var edcal = {
98
  * True if we are in the middle of dragging a post
99
  */
100
  inDrag: false,
101
-
102
  /*
103
  True if the calendar is in the process of queueing scrolling
104
  during a drag.
@@ -106,14 +106,14 @@ var edcal = {
106
  isDragScrolling: false,
107
 
108
  /*
109
- * This is the format we use to dates that we use as IDs in the
110
  * calendar. It is independant of the visible date which is
111
  * formatted based on the user's locale.
112
  */
113
  internalDateFormat: 'ddMMyyyy',
114
-
115
  /*
116
- This is the position of the calendar on the screen in pixels.
117
  It is an array with two fields: top and bottom.
118
  */
119
  position: null,
@@ -127,22 +127,22 @@ var edcal = {
127
  * This is the first day of the next month
128
  */
129
  firstDayOfNextMonth: null,
130
-
131
  /*
132
  * The date format used by wordpress
133
  */
134
- wp_dateFormat: "yyyy-MM-dd",
135
-
136
  /*
137
  * The cache of dates we have already loaded posts for.
138
  */
139
- cacheDates : [],
140
-
141
  /*
142
  * The ID of the timer we use to batch new post requests
143
  */
144
  tID: null,
145
-
146
  /*
147
  * The number of steps moving for this timer.
148
  */
@@ -162,7 +162,7 @@ var edcal = {
162
  * The constant for the nonce error
163
  */
164
  NONCE_ERROR: 6,
165
-
166
  /*
167
  The direction the calendar last moved.
168
  true = down = to the future
@@ -170,14 +170,14 @@ var edcal = {
170
 
171
  */
172
  currentDirection: true,
173
-
174
  /*
175
  This date is our index. When the calendar moves we
176
  update this date to indicate the next rows we need
177
  to add.
178
  */
179
  _wDate: Date.today(),
180
-
181
  /*
182
  * The date since the previous move
183
  */
@@ -186,26 +186,26 @@ var edcal = {
186
  /*
187
  * This is a number from 0-6 indicating when the start
188
  * of the week is. The user sets this in the Settings >
189
- * General page and it is a single value for the entire
190
  * server. We are setting this value in edcal.php
191
  */
192
  startOfWeek: null,
193
-
194
  /*
195
  A cache of all the posts we have loaded so far. The
196
  data structure is:
197
-
198
  posts [date - ddMMMyyyy][posts array - post object from JSON data]
199
  */
200
- posts: new Array(50),
201
-
202
  /*
203
  IE will sometimes fire the resize event twice for the same resize
204
  action. We save it so we only resize the calendar once and avoid
205
  any flickering.
206
  */
207
  windowHeight: 0,
208
-
209
  /*
210
  This function aligns the grid in two directions. There
211
  is a vertical grid with a row of each week and a horizontal
@@ -216,46 +216,46 @@ var edcal = {
216
  var y = 0;
217
  var count = 1;
218
 
219
- jQuery(gridid).each(function(){
220
- jQuery(this).css("position", "relative");
221
-
222
- jQuery(this).children("div").each(function(){
223
  jQuery(this).css({
224
- width: cellWidth + "%",
225
- height: cellHeight + "%",
226
- position: "absolute",
227
- left: x + "%",
228
- top: y + "%"
229
  });
230
-
231
  if ((count % cols) === 0) {
232
  x = 0;
233
  y += cellHeight + padding;
234
  } else {
235
  x += cellWidth + padding;
236
  }
237
-
238
  count++;
239
  });
240
  });
241
  },
242
-
243
  /*
244
  This is a helper function to align the calendar so we don't
245
  have to change the cell sizes in multiple places.
246
  */
247
  alignCal: function() {
248
- edcal.alignGrid("#cal", 1, 100, (100 / edcal.weeksPref) - 1, 1);
249
  },
250
 
251
-
252
  /*
253
  This function creates the days header at the top of the
254
  calendar.
255
  */
256
  createDaysHeader: function() {
257
  /*
258
- * The first day of the week in the calendar depends on
259
  * a wordpress setting and maybe the server locale. This
260
  * means we need to determine the days of the week dynamically.
261
  * Luckily the Date.js library already has these strings
@@ -266,14 +266,14 @@ var edcal = {
266
  var date = Date.today().next().sunday();
267
 
268
  /*
269
- * We need to call nextStartOfWeek to make sure the
270
  * edcal.startOfWeek variable gets initialized.
271
  */
272
  edcal.nextStartOfWeek(date);
273
-
274
 
275
- var html = '<div class="dayheadcont"><div class="dayhead firstday">' +
276
- date.add(edcal.startOfWeek).days().toString('dddd') +
 
277
  '</div>';
278
 
279
  html += '<div class="dayhead">' + date.add(1).days().toString('dddd') + '</div>';
@@ -282,10 +282,10 @@ var edcal = {
282
  html += '<div class="dayhead">' + date.add(1).days().toString('dddd') + '</div>';
283
  html += '<div class="dayhead">' + date.add(1).days().toString('dddd') + '</div>';
284
  html += '<div class="dayhead lastday">' + date.add(1).days().toString('dddd') + '</div>';
285
-
286
- jQuery("#cal_cont").prepend(html);
287
-
288
- edcal.alignGrid(".dayheadcont", 7, 13.8, 100, 0.5);
289
  },
290
 
291
  /*
@@ -302,16 +302,16 @@ var edcal = {
302
  /*
303
  * Date is before today
304
  */
305
- daystyle = "beforeToday";
306
  } else {
307
  /*
308
  * Date is after today
309
  */
310
- daystyle = "todayAndAfter";
311
  }
312
  if (!edcal.firstDayOfMonth) {
313
  /*
314
- * We only need to figure out the first and last day
315
  * of the month once
316
  */
317
  edcal.firstDayOfMonth = Date.today().moveToFirstDayOfMonth().clearTime();
@@ -319,32 +319,32 @@ var edcal = {
319
  }
320
  if (date.between(edcal.firstDayOfMonth, edcal.firstDayOfNextMonth)) {
321
  /*
322
- * If the date isn't before the first of the
323
- * month and it isn't after the last of the
324
  * month then it is in the current month.
325
  */
326
- monthstyle = "month-present";
327
  } else if (date.compareTo(edcal.firstDayOfMonth) == 1) {
328
  /*
329
  * Then the date is after the current month
330
  */
331
- monthstyle = "month-future";
332
  } else if (date.compareTo(edcal.firstDayOfNextMonth) == -1) {
333
  /*
334
  * Then the date is before the current month
335
  */
336
- monthstyle = "month-past";
337
  }
338
-
339
- if (date.toString("dd") == "01") {
340
  /*
341
  * This this date is the first day of the month
342
  */
343
  daystyle += ' firstOfMonth';
344
  }
345
-
346
-
347
- return monthstyle+' '+daystyle;
348
  },
349
 
350
  /*
@@ -355,9 +355,9 @@ var edcal = {
355
  if (edcal.inDrag) {
356
  return;
357
  }
358
-
359
- var createLink = jQuery("#" + dayid + " a.daynewlink");
360
- createLink.css("display", "block");
361
  createLink.bind('click', edcal.addPost);
362
  },
363
 
@@ -366,18 +366,18 @@ var edcal = {
366
  outside of the calendar day.
367
  */
368
  hideAddPostLink: function(/*string*/ dayid) {
369
- var link = jQuery("#" + dayid + " a.daynewlink").hide();
370
  link.unbind('click', edcal.addPost);
371
  },
372
-
373
  /*
374
  Creates a row of the calendar and adds all of the CSS classes
375
  and listeners for each calendar day.
376
  */
377
  createRow: function(/*jQuery*/ parent, /*bool*/ append) {
378
  var _date = edcal._wDate.clone();
379
-
380
- var newrow = '<div class="rowcont" id="' + 'row' + edcal._wDate.toString(edcal.internalDateFormat) + '">' +
381
  '<div id="' + 'row' + edcal._wDate.toString(edcal.internalDateFormat) + 'row" class="row">';
382
  for (var i = 0; i < 7; i++) {
383
  /*
@@ -385,52 +385,52 @@ var edcal = {
385
  * could do this with the JQuery live function, but there are a lot
386
  * of days in the calendar and the live function gets a little slow.
387
  */
388
- newrow += '<div onmouseover="edcal.showAddPostLink(\'' + _date.toString(edcal.internalDateFormat) + '\');" ' +
389
- 'onmouseout="edcal.hideAddPostLink(\'' + _date.toString(edcal.internalDateFormat) + '\');" ' +
390
- 'id="' + _date.toString(edcal.internalDateFormat) + '" class="day ' +
391
- edcal.getDateClass(_date) + ' ' +
392
- _date.toString("dddd").toLowerCase() + ' month-' +
393
- _date.toString("MM").toLowerCase() + '">';
394
-
395
  newrow += '<div class="dayobj">';
396
-
397
- newrow += '<a href="#" adddate="' + _date.toString("MMMM d") + '" class="daynewlink" title="' + edcal.str_newpost + _date.toString("MMMM d") + '" ' +
398
  'onclick="return false;">' + edcal.str_addPostLink + '</a>';
399
-
400
- if (_date.toString("dd") == "01") {
401
- newrow += '<div class="daylabel">' + _date.toString("MMM d");
402
  } else {
403
- newrow += '<div class="daylabel">' + _date.toString("d");
404
  }
405
-
406
-
407
  newrow += '</div>';
408
 
409
  newrow += '<ul class="postlist">';
410
 
411
  newrow += edcal.getPostItems(_date.toString(edcal.internalDateFormat));
412
-
413
  newrow += '</ul>';
414
-
415
  newrow += '</div>';
416
  newrow += '</div>';
417
  _date.add(1).days();
418
  }
419
-
420
  newrow += '</div></div>';
421
-
422
  if (append) {
423
  parent.append(newrow);
424
-
425
  } else {
426
  parent.prepend(newrow);
427
  }
428
-
429
  /*
430
  * This is the horizontal alignment of an individual week
431
  */
432
- edcal.alignGrid("#row" + edcal._wDate.toString(edcal.internalDateFormat) + "row", 7, 13.9, 100, 0.5);
433
-
434
  edcal.draggablePost('#row' + edcal._wDate.toString(edcal.internalDateFormat) + ' li.post');
435
 
436
  jQuery('#row' + edcal._wDate.toString(edcal.internalDateFormat) + ' > div > div.day').droppable({
@@ -443,8 +443,8 @@ var edcal = {
443
  fragile, but it is much faster than doing date
444
  arithmetic every time the mouse twitches.
445
  */
446
- if (jQuery(this).hasClass("beforeToday")) {
447
- if (ui.hasClass("draft")) {
448
  return true;
449
  } else {
450
  return false;
@@ -459,10 +459,10 @@ var edcal = {
459
  //output('dropped ui.draggable.attr("id"): ' + ui.draggable.attr("id"));
460
  //output('dropped on jQuery(this).attr("id"): ' + jQuery(this).attr("id"));
461
  //output('ui.draggable.html(): ' + ui.draggable.html());
462
-
463
- var dayId = ui.draggable.parent().parent().parent().attr("id");
464
 
465
- edcal.doDrop(dayId, ui.draggable.attr("id"), jQuery(this).attr("id"));
 
 
466
  }
467
  });
468
 
@@ -478,13 +478,13 @@ var edcal = {
478
 
479
  // Step 0. Get the post object from the map
480
  var post = edcal.findPostForId(parentId, postId);
481
-
482
  // Step 1. Remove the post from the posts map
483
  edcal.removePostFromMap(parentId, postId);
484
 
485
  // Step 2. Remove the old element from the old parent.
486
  jQuery('#' + postId).remove();
487
-
488
  // Step 3. Add the item to the new DOM parent
489
  jQuery('#' + newDate + ' .postlist').append(edcal.createPostItem(post, newDate));
490
 
@@ -505,13 +505,13 @@ var edcal = {
505
  */
506
  draggablePost: function(/*post selector*/ post) {
507
  jQuery(post).each(function() {
508
- var postObj = edcal.findPostForId(jQuery(this).parent().parent().parent().attr("id"),
509
- jQuery(this).attr("id"));
510
  if (edcal.isPostMovable(postObj)) {
511
- jQuery(this).draggable({
512
  revert: 'invalid',
513
  appendTo: 'body',
514
- helper: "clone",
515
  distance: 1,
516
  addClasses: false,
517
  start: function() {
@@ -526,7 +526,7 @@ var edcal = {
526
  scroll: false,
527
  refreshPositions: true
528
  });
529
- jQuery(this).addClass("draggable");
530
  }
531
  });
532
  },
@@ -542,7 +542,7 @@ var edcal = {
542
  }
543
 
544
  edcal.isDragScrolling = true;
545
-
546
  if (event.pageY < (edcal.position.top + 10)) {
547
  /*
548
  This means we're close enough to the top of the calendar to
@@ -568,7 +568,7 @@ var edcal = {
568
  edcal.isDragScrolling = false;
569
  }, 300);
570
  },
571
-
572
  /*
573
  This is a utility method to find a post and remove it
574
  from the cache map.
@@ -577,16 +577,16 @@ var edcal = {
577
  if (edcal.posts[dayobjId]) {
578
  for (var i = 0; i < edcal.posts[dayobjId].length; i++) {
579
  if (edcal.posts[dayobjId][i] &&
580
- "post-" + edcal.posts[dayobjId][i].id === postId) {
581
  edcal.posts[dayobjId][i] = null;
582
  return true;
583
  }
584
  }
585
  }
586
-
587
  return false;
588
  },
589
-
590
  /*
591
  * Adds a post to an already existing calendar day.
592
  */
@@ -596,7 +596,7 @@ var edcal = {
596
  * be much more adaptable to reference the class by name, but this is
597
  * significantly faster. Especially on IE.
598
  */
599
- jQuery('#' + dayobjId + " > div > ul").append(edcal.createPostItem(post, dayobjId));
600
  },
601
 
602
  /*
@@ -612,17 +612,17 @@ var edcal = {
612
  Deletes the post specified. Will only be executed once the user clicks the confirm link to proceed.
613
  */
614
  deletePost: function(/*Post ID*/ postId, /*function*/ callback) {
615
-
616
- var url = edcal.ajax_url() + "&action=edcal_deletepost&postid=" + postId;
617
-
618
- jQuery.ajax( {
619
  url: url,
620
- type: "POST",
621
  processData: false,
622
  timeout: 100000,
623
- dataType: "json",
624
- success: function(res) {
625
- edcal.removePostItem(res.post.date, "post-" + res.post.id);
626
  if (res.error) {
627
  /*
628
  * If there was an error we need to remove the dropped
@@ -642,7 +642,7 @@ var edcal = {
642
  error: function(xhr) {
643
  edcal.showError(edcal.general_error);
644
  if (xhr.responseText) {
645
- edcal.output("deletePost xhr.responseText: " + xhr.responseText);
646
  }
647
  }
648
  });
@@ -657,41 +657,41 @@ var edcal = {
657
  confirmDelete: function(/*string*/ posttitle) {
658
  if (confirm(edcal.str_del_msg1 + posttitle + edcal.str_del_msg2)) {
659
  return true;
660
- // [wes] might be better to call deletePost from here directly, rather than return control back to the agent... which will then follow the link and call deletePost
661
  } else {
662
  return false;
663
  }
664
  },
665
-
666
  /*
667
  This is a simple function that creates the AJAX URL with the
668
  nonce value generated in edcal.php.
669
  */
670
  ajax_url: function() {
671
- return ajaxurl + "?_wpnonce=" + edcal.wp_nonce;
672
  },
673
 
674
  /*
675
  NOT USED
676
  */
677
  getMediaBar: function() {
678
- return jQuery("#cal_mediabar").html();
679
  },
680
-
681
  /*
682
  * Called when the "Add a post" link is clicked.
683
  * Sets up a post object and displays the add form
684
  */
685
- addPost: function( ) {
686
- jQuery("#newPostScheduleButton").addClass("disabled");
687
-
688
- var date = jQuery(this).parent().parent().attr("id");
689
-
690
  var formattedtime = '10:00';
691
  if (edcal.timeFormat !== 'H:i') {
692
- formattedtime += " AM";
693
  }
694
-
695
  var post = {
696
  id: 0,
697
  date: date,
@@ -701,7 +701,7 @@ var edcal = {
701
  edcal.showForm(post);
702
  return false;
703
  },
704
-
705
  /*
706
  * Called when the Edit link for a post is clicked.
707
  * Gets post details via an AJAX call and displays the edit form
@@ -709,35 +709,35 @@ var edcal = {
709
  */
710
  editPost: function(/*int*/ post_id) {
711
  // Un-disable the save buttons because we're editing
712
- jQuery("#newPostScheduleButton").removeClass("disabled");
713
-
714
  // Editing, so we need to make an ajax call to get body of post
715
  edcal.getPost(post_id, edcal.showForm);
716
  return false;
717
  },
718
-
719
-
720
  /*
721
  * When the user presses the new post link on each calendar cell they get
722
  * a tooltip which prompts them to add or edit a post. Once
723
  * they hit save we call this function.
724
- *
725
  * post - post object containing data for the post
726
  * doEdit - should we edit the post immediately? if true we send the user
727
  * to the edit screen for their new post.
728
  */
729
  savePost: function(/*object*/ post, /*boolean*/ doEdit, /*boolean*/ doPublish, /*function*/ callback) {
730
- if(typeof(post) === 'undefined' || post === null) {
731
  post = edcal.serializePost();
732
  }
733
-
734
- if (!post.title || post.title === "") {
735
  return;
736
  }
737
-
738
- edcal.output("savePost(" + post.date + ", " + post.title + ")");
739
 
740
- jQuery("#edit-slug-buttons").addClass("tiploading");
 
 
741
 
742
  /*
743
  The date.js library has a bug where it gives the wrong
@@ -745,46 +745,50 @@ var edcal = {
745
  but we still need to work aorund the issue. Hackito
746
  ergo sum.
747
  */
748
- if (post.time.toUpperCase() === "12:00 PM") {
749
- post.time = "12:00";
750
- } else if (post.time.toUpperCase() === "12:30 PM") {
751
- post.time = "12:30";
752
- } else if (post.time.toUpperCase() === "12:00 AM") {
753
- post.time = "00:00";
754
- } else if (post.time.toUpperCase() === "12:30 AM") {
755
- post.time = "00:30";
756
  }
757
 
758
  var time;
759
- if(post.time !== '') {
760
  time = Date.parse(post.time);
761
  } else {
762
  time = Date.parse('10:00:00'); // If we don't have a time set, default it to 10am
763
  }
764
-
765
  var formattedtime = time.format('H:i:s');
766
-
767
- var formattedDate = encodeURIComponent(edcal.getDayFromDayId(post.date).toString(edcal.wp_dateFormat) + " " + formattedtime);
768
- var url = edcal.ajax_url() + "&action=edcal_savepost&";
769
- var postData = "date=" + formattedDate +
770
- "&title=" + encodeURIComponent(post.title) +
771
- "&content=" + encodeURIComponent(post.content) +
772
- "&id=" + encodeURIComponent(post.id) +
773
- "&status=" + encodeURIComponent(post.status);
774
-
 
 
 
 
775
  if (doPublish) {
776
- postData += "&dopublish=" + encodeURIComponent('future');
777
  }
778
 
779
- jQuery.ajax( {
780
  url: url,
781
- type: "POST",
782
  processData: false,
783
  data: postData,
784
  timeout: 100000,
785
- dataType: "json",
786
  success: function(res) {
787
- jQuery("#edit-slug-buttons").removeClass("tiploading");
788
  jQuery('#tooltip').hide();
789
  if (res.error) {
790
  /*
@@ -796,22 +800,22 @@ var edcal = {
796
  }
797
  return;
798
  }
799
-
800
  if (!res.post) {
801
- edcal.showError("There was an error creating a new post for your blog.");
802
  } else {
803
  if (doEdit) {
804
  /*
805
  * If the user wanted to edit the post then we redirect
806
  * them to the edit page.
807
  */
808
- window.location = res.post.editlink.replace("&amp;", "&");
809
  } else {
810
-
811
  if (res.post.id) {
812
- edcal.removePostItem(res.post.date, "post-" + res.post.id);
813
  }
814
-
815
  edcal.addPostItem(res.post, res.post.date);
816
  edcal.addPostItemDragAndToolltip(res.post.date);
817
  }
@@ -822,42 +826,42 @@ var edcal = {
822
  }
823
  },
824
  error: function(xhr) {
825
- jQuery("#edit-slug-buttons").removeClass("tiploading");
826
  jQuery('#tooltip').hide();
827
  edcal.showError(edcal.general_error);
828
  if (xhr.responseText) {
829
- edcal.output("savePost xhr.responseText: " + xhr.responseText);
830
  }
831
  }
832
  });
833
  return false;
834
  },
835
-
836
  /*
837
  * Collects form values for the post inputted by the user into an object
838
  */
839
  serializePost: function() {
840
  var post = {};
841
-
842
  jQuery('#tooltip').find('input, textarea, select').each(function() {
843
  post[this.name] = this.value;
844
  });
845
  return post;
846
  },
847
-
848
  /*
849
  * Accepts new or existing post data and then populates text fields as necessary
850
  */
851
  showForm: function(post) {
852
  edcal.resetForm();
853
-
854
  // show tooltip
855
  jQuery('#tooltip').center().show();
856
-
857
- if(!post.id) {
858
  jQuery('#tooltiptitle').text(edcal.str_newpost_title + post.formatteddate);
859
  } else {
860
- jQuery('#tooltiptitle').text(edcal.str_edit_post_title + edcal.getDayFromDayId(post.date).toString(edcal.previewDateFormat));
861
 
862
  // sets the read-only author field
863
  //jQuery('#edcal-author-p').html(post.author);
@@ -866,11 +870,11 @@ var edcal = {
866
  jQuery('#edcal-title-new-field').val(post.title);
867
  jQuery('#content').val(post.content);
868
  }
869
-
870
- if (post.status === "future") {
871
  jQuery('#newPostScheduleButton').text(edcal.str_update);
872
  }
873
-
874
  if (post.status) {
875
  jQuery('#edcal-status').val(post.status);
876
  edcal.updatePublishButton();
@@ -878,7 +882,7 @@ var edcal = {
878
  jQuery('#edcal-status').val('draft');
879
  jQuery('#newPostScheduleButton').text(edcal.str_save);
880
  }
881
-
882
  /*
883
  If you have a status that isn't draft or future we
884
  just make it read only.
@@ -888,19 +892,19 @@ var edcal = {
888
  jQuery('#edcal-status').append('<option class="temp" value="' + post.status + '">' + post.status + '</option>');
889
  jQuery('#edcal-status').val(post.status);
890
  }
891
-
892
-
893
-
894
  if (edcal.getDayFromDayId(post.date).compareTo(Date.today()) == -1) {
895
  /*
896
  * We only allow drafts in the past
897
  */
898
  jQuery('#edcal-status').attr('disabled', 'true');
899
  }
900
-
901
  var time = post.time;
902
  jQuery('#edcal-time').val(time);
903
-
904
  // set hidden fields: post.date, post.id
905
  jQuery('#edcal-date').val(post.date);
906
  jQuery('#edcal-id').val(post.id);
@@ -909,8 +913,8 @@ var edcal = {
909
  * Put the focus in the post title field when the tooltip opens.
910
  */
911
 
912
- jQuery("#edcal-title-new-field").focus();
913
- jQuery("#edcal-title-new-field").select();
914
 
915
  /*
916
  tb_init('a.thickbox, area.thickbox, input.thickbox');
@@ -926,50 +930,49 @@ var edcal = {
926
  });
927
  */
928
  },
929
-
930
  /*
931
  * Hides the add/edit form
932
  */
933
- hideForm: function( ) {
934
  jQuery('#tooltip').hide();
935
  edcal.resetForm();
936
  },
937
-
938
  /*
939
  * Clears all the input values in the add/edit form
940
  */
941
- resetForm: function( ) {
942
  jQuery('#tooltip').find('input, textarea, select').each(function() {
943
  this.value = '';
944
  });
945
-
946
  jQuery('#edcal-status').removeAttr('disabled');
947
-
948
  jQuery('#newPostScheduleButton').text(edcal.str_publish);
949
-
950
  jQuery('#tooltiptitle').text('');
951
  //jQuery('#edcal-author-p').html('');
952
-
953
  jQuery('#edcal-status').removeAttr('disabled');
954
-
955
  jQuery('#edcal-status .temp').remove();
956
  },
957
-
958
  /*
959
  Creates the HTML for a post item and adds the data for
960
  the post to the posts cache.
961
  */
962
  createPostItem: function(/*post*/ post, /*string*/ dayobjId) {
963
- var postHtml = edcal.getPostItemString(post);
964
  if (!edcal.posts[dayobjId]) {
965
- edcal.posts[dayobjId] = new Array(0);
966
  }
967
 
968
  edcal.posts[dayobjId][edcal.posts[dayobjId].length] = post;
969
-
970
- return postHtml;
971
  },
972
-
973
  /*
974
  Finds the post object for the specified post ID in the
975
  specified day.
@@ -978,13 +981,13 @@ var edcal = {
978
  if (edcal.posts[dayobjId]) {
979
  for (var i = 0; i < edcal.posts[dayobjId].length; i++) {
980
  if (edcal.posts[dayobjId][i] &&
981
- "post-" + edcal.posts[dayobjId][i].id === postId) {
982
  return edcal.posts[dayobjId][i];
983
  }
984
  }
985
  }
986
  },
987
-
988
  /*
989
  * Removes a post from the HTML and the posts cache.
990
  */
@@ -992,21 +995,21 @@ var edcal = {
992
  if (edcal.findPostForId(dayobjId, postId)) {
993
  for (var i = 0; i < edcal.posts[dayobjId].length; i++) {
994
  if (edcal.posts[dayobjId][i] &&
995
- "post-" + edcal.posts[dayobjId][i].id === postId) {
996
  edcal.posts[dayobjId][i] = null;
997
- jQuery("#" + postId).remove();
998
  }
999
  }
1000
  }
1001
  },
1002
-
1003
  /*
1004
  Gets all the post items for the specified day from
1005
  the post cache.
1006
  */
1007
  getPostItems: function(/*string*/ dayobjId) {
1008
- var postsString = "";
1009
-
1010
  if (edcal.posts[dayobjId]) {
1011
  for (var i = 0; i < edcal.posts[dayobjId].length; i++) {
1012
  if (edcal.posts[dayobjId][i]) {
@@ -1017,23 +1020,23 @@ var edcal = {
1017
 
1018
  return postsString;
1019
  },
1020
-
1021
  /*
1022
  This function shows the action links for the post with the
1023
  specified ID.
1024
  */
1025
  showActionLinks: function(/*string*/ postid) {
1026
  var post = edcal.findPostForId(jQuery('#' + postid).parent().parent().parent().attr('id'), postid);
1027
-
1028
  if (edcal.inDrag || !edcal.isPostEditable(post)) {
1029
  return;
1030
  }
1031
-
1032
  var elem = jQuery('#' + postid + ' > div.postactions');
1033
-
1034
  elem.show();
1035
-
1036
-
1037
  if (elem.parent().position().top + elem.parent().height() > elem.parent().parent().height()) {
1038
  /*
1039
  This means the action links probably won't be visible and we need to
@@ -1042,8 +1045,8 @@ var edcal = {
1042
  var p = jQuery('#' + postid + ' > div.postactions').parent().parent();
1043
  p.scrollTop(p.scrollTop() + 45);
1044
  }
1045
- },
1046
-
1047
  /*
1048
  Hides the action links for the post with the specified
1049
  post ID.
@@ -1058,9 +1061,9 @@ var edcal = {
1058
  This is based on the post date
1059
  */
1060
  isPostMovable: function(/*post*/ post) {
1061
- return post.editlink && post.status !== "publish";
1062
  },
1063
-
1064
  /*
1065
  Returns true if the post is editable and false otherwise.
1066
  This is based on user permissions
@@ -1068,36 +1071,36 @@ var edcal = {
1068
  isPostEditable: function(/*post*/ post) {
1069
  return post.editlink;
1070
  },
1071
-
1072
  /*
1073
  Returns readonly if the post isn't editable
1074
  */
1075
  getPostEditableClass: function(/*post*/ post) {
1076
  if (post.editlink) {
1077
- return "";
1078
  } else {
1079
- return "readonly";
1080
  }
1081
  },
1082
-
1083
  /*
1084
  * Gets the HTML string for a post.
1085
  */
1086
  getPostItemString: function(/*post*/ post) {
1087
  var posttitle = post.title;
1088
 
1089
- if (posttitle === "") {
1090
- posttitle = "[No Title]";
1091
  }
1092
 
1093
  if (edcal.statusPref) {
1094
- if (post.status === "draft" &&
1095
  post.sticky === '1') {
1096
  /*
1097
  * Then this post is a sticky draft
1098
  */
1099
  posttitle += edcal.str_draft_sticky;
1100
- } else if (post.status === "pending" &&
1101
  post.sticky === '1') {
1102
  /*
1103
  * Then this post is a sticky pending post
@@ -1105,13 +1108,13 @@ var edcal = {
1105
  posttitle += edcal.str_pending_sticky;
1106
  } else if (post.sticky === '1') {
1107
  posttitle += edcal.str_sticky;
1108
- } else if (post.status === "pending") {
1109
  posttitle += edcal.str_pending;
1110
- } else if (post.status === "draft") {
1111
  posttitle += edcal.str_draft;
1112
- } else if (post.status !== "publish" &&
1113
- post.status !== "future" &&
1114
- post.status !== "pending") {
1115
  /*
1116
  There are some WordPress plugins that let you specify
1117
  custom post status. In that case we just want to show
@@ -1124,34 +1127,34 @@ var edcal = {
1124
  if (edcal.timePref) {
1125
  posttitle = '<span class="posttime">' + post.formattedtime + '</span> ' + posttitle;
1126
  }
1127
-
1128
  if (edcal.authorPref) {
1129
- posttitle = posttitle + ' ' + edcal.str_by + ' ' + '<span class="postauthor">' + post.author + '</span>';
1130
  }
1131
-
1132
  var classString = '';
1133
-
1134
  if (edcal.isPostMovable(post)) {
1135
- return '<li onmouseover="edcal.showActionLinks(\'post-' + post.id + '\');" ' +
1136
- 'onmouseout="edcal.hideActionLinks(\'post-' + post.id + '\');" ' +
1137
- 'id="post-' + post.id + '" class="post ' + post.status + ' ' + edcal.getPostEditableClass(post) + '"><div class="postlink ' + classString + '">' + posttitle + '</div>' +
1138
- '<div class="postactions">' +
1139
  '<a href="' + post.editlink + '">' + edcal.str_edit + '</a> | ' +
1140
- '<a href="#" onclick="edcal.editPost('+ post.id +'); return false;">' + edcal.str_quick_edit + '</a> | ' +
1141
  '<a href="' + post.dellink + '" onclick="return edcal.confirmDelete(\'' + post.title + '\');">' + edcal.str_del + '</a> | ' +
1142
- '<a href="' + post.permalink + '">' + edcal.str_view + '</a>' +
1143
  '</div></li>';
1144
  } else {
1145
- return '<li onmouseover="edcal.showActionLinks(\'post-' + post.id + '\');" ' +
1146
- 'onmouseout="edcal.hideActionLinks(\'post-' + post.id + '\');" ' +
1147
- 'id="post-' + post.id + '" class="post ' + post.status + ' ' + edcal.getPostEditableClass(post) + '"><div class="postlink ' + classString + '">' + posttitle + '</div>' +
1148
- '<div class="postactions">' +
1149
  '<a href="' + post.editlink + '">' + edcal.str_republish + '</a> | ' +
1150
- '<a href="' + post.permalink + '">' + edcal.str_view + '</a>' +
1151
  '</div></li>';
1152
  }
1153
  },
1154
-
1155
  /*
1156
  Finds the calendar cell for the current day and adds the
1157
  class "today" to that cell.
@@ -1161,9 +1164,9 @@ var edcal = {
1161
  We want to set a class for the cell that represents the current day so we can
1162
  give it a background color.
1163
  */
1164
- jQuery('#' + Date.today().toString(edcal.internalDateFormat)).addClass("today");
1165
  },
1166
-
1167
  /*
1168
  Most browsers need us to set a calendar height in pixels instead
1169
  of percent. This function get the correct pixel height for the
@@ -1171,27 +1174,27 @@ var edcal = {
1171
  */
1172
  getCalHeight: function() {
1173
  var myHeight = jQuery(window).height() - jQuery('#footer').height() - jQuery('#wphead').height() - 150;
1174
-
1175
  /*
1176
  We don't want to make the calendar too short even if the
1177
  user's screen is super short.
1178
  */
1179
  return Math.max(myHeight, 500);
1180
  },
1181
-
1182
  /*
1183
  Moves the calendar a certain number of steps in the specified direction.
1184
  True moves the calendar down into the future and false moves the calendar
1185
  up into the past.
1186
  */
1187
  move: function(/*int*/ steps, /*boolean*/ direction, /*function*/ callback) {
1188
- /*
1189
  * If the add/edit post form is visible, don't go anywhere.
1190
  */
1191
- if(jQuery('#tooltip').is(':visible')) {
1192
  return;
1193
  }
1194
-
1195
  /*
1196
  The working date is a marker for the last calendar row we created.
1197
  If we are moving forward that will be the last row, if we are moving
@@ -1208,34 +1211,34 @@ var edcal = {
1208
  edcal.steps = 0;
1209
  edcal.moveDate = edcal._wDate;
1210
  }
1211
-
1212
  edcal.currentDirection = direction;
1213
-
1214
  var i;
1215
-
1216
-
1217
  if (direction) {
1218
  for (i = 0; i < steps; i++) {
1219
- jQuery("#cal > div:first").remove();
1220
- edcal.createRow(jQuery("#cal"), true);
1221
  edcal._wDate.add(7).days();
1222
  }
1223
  edcal.alignCal();
1224
  } else {
1225
  for (i = 0; i < steps; i++) {
1226
- jQuery("#cal > div:last").remove();
1227
- edcal.createRow(jQuery("#cal"), false);
1228
  edcal._wDate.add(-7).days();
1229
  }
1230
  edcal.alignCal();
1231
  }
1232
-
1233
  edcal.setClassforToday();
1234
  edcal.setDateLabel();
1235
 
1236
  /*
1237
- * If the user clicks quickly or uses the mouse wheel they can
1238
- * get a lot of move events very quickly and we need to batch
1239
  * them up together. We set a timeout and clear it if there is
1240
  * another move before the timeout happens.
1241
  */
@@ -1247,18 +1250,18 @@ var edcal = {
1247
  }
1248
 
1249
  edcal.tID = setTimeout(function() {
1250
-
1251
  /*
1252
- * Now that we are done moving the calendar we need to get the posts for the
1253
  * new dates. We want to load the posts between the place the calendar was
1254
  * at when the user started moving it and the place the calendar is at now.
1255
  */
1256
  if (!direction) {
1257
- edcal.getPosts(edcal._wDate.clone(),
1258
  edcal._wDate.clone().add(7 * (edcal.steps + 1)).days(),
1259
  callback);
1260
  } else {
1261
- edcal.getPosts(edcal._wDate.clone().add(-7 * (edcal.steps + 1)).days(),
1262
  edcal._wDate.clone(),
1263
  callback);
1264
  }
@@ -1267,7 +1270,7 @@ var edcal = {
1267
  edcal.tID = null;
1268
  edcal.moveDate = edcal._wDate;
1269
  }, 1000);
1270
-
1271
  if (direction) {
1272
  /*
1273
  If we are going into the future then wDate is way in the
@@ -1291,32 +1294,32 @@ var edcal = {
1291
  issue by adding the spaces back before we parse.
1292
  */
1293
  getDayFromDayId: function(/*dayId*/ day) {
1294
- return Date.parseExact(day.substring(2, 4) + '/' + day.substring(0, 2) + '/' + day.substring(4), "MM/dd/yyyy");
1295
  },
1296
-
1297
  /*
1298
  This is a helper method to set the date label on the top of
1299
  the calendar. It looks like November 2009-December2009
1300
  */
1301
  setDateLabel: function(year) {
1302
- var api = jQuery("#edcal_scrollable").scrollable();
1303
  var items = api.getVisibleItems();
1304
-
1305
  /*
1306
  We need to get the first day in the first week and the
1307
  last day in the last week. We call children twice to
1308
  work around a small JQuery issue.
1309
  */
1310
- var firstDate = edcal.getDayFromDayId(items.eq(0).children(".row").children(".day:first").attr("id"));
1311
- var lastDate = edcal.getDayFromDayId(items.eq(edcal.weeksPref - 1).children(".row").children(".day:last").attr("id"));
1312
-
1313
- jQuery("#currentRange").text(firstDate.toString("MMMM yyyy") + " - " + lastDate.toString("MMMM yyyy"));
1314
  },
1315
 
1316
  /*
1317
  * We want the calendar to start on the day of the week that matches the country
1318
  * code in the locale. If their full locale is en-US, that means the country
1319
- * code is US.
1320
  *
1321
  * This is the full list of start of the week days from unicode.org
1322
  * http://unicode.org/repos/cldr/trunk/common/supplemental/supplementalData.xml
@@ -1326,76 +1329,76 @@ var edcal = {
1326
  if (edcal.startOfWeek === null) {
1327
  if (edcal.locale) {
1328
  var local = edcal.locale.toUpperCase();
1329
-
1330
- if (edcal.endsWith(local, "AS") ||
1331
- edcal.endsWith(local, "AZ") ||
1332
- edcal.endsWith(local, "BW") ||
1333
- edcal.endsWith(local, "CA") ||
1334
- edcal.endsWith(local, "CN") ||
1335
- edcal.endsWith(local, "FO") ||
1336
- edcal.endsWith(local, "GB") ||
1337
- edcal.endsWith(local, "GE") ||
1338
- edcal.endsWith(local, "GL") ||
1339
- edcal.endsWith(local, "GU") ||
1340
- edcal.endsWith(local, "HK") ||
1341
- edcal.endsWith(local, "IE") ||
1342
- edcal.endsWith(local, "IL") ||
1343
- edcal.endsWith(local, "IN") ||
1344
- edcal.endsWith(local, "IS") ||
1345
- edcal.endsWith(local, "JM") ||
1346
- edcal.endsWith(local, "JP") ||
1347
- edcal.endsWith(local, "KG") ||
1348
- edcal.endsWith(local, "KR") ||
1349
- edcal.endsWith(local, "LA") ||
1350
- edcal.endsWith(local, "MH") ||
1351
- edcal.endsWith(local, "MN") ||
1352
- edcal.endsWith(local, "MO") ||
1353
- edcal.endsWith(local, "MP") ||
1354
- edcal.endsWith(local, "MT") ||
1355
- edcal.endsWith(local, "NZ") ||
1356
- edcal.endsWith(local, "PH") ||
1357
- edcal.endsWith(local, "PK") ||
1358
- edcal.endsWith(local, "SG") ||
1359
- edcal.endsWith(local, "SY") ||
1360
- edcal.endsWith(local, "TH") ||
1361
- edcal.endsWith(local, "TT") ||
1362
- edcal.endsWith(local, "TW") ||
1363
- edcal.endsWith(local, "UM") ||
1364
- edcal.endsWith(local, "US") ||
1365
- edcal.endsWith(local, "UZ") ||
1366
- edcal.endsWith(local, "VI") ||
1367
- edcal.endsWith(local, "ZW")) {
1368
 
1369
  /*
1370
  * Sunday
1371
  */
1372
  edcal.startOfWeek = 0;
1373
- } else if (edcal.endsWith(local, "MV")) {
1374
  /*
1375
  * Friday
1376
  */
1377
  edcal.startOfWeek = 5;
1378
- } else if (edcal.endsWith(local, "AF") ||
1379
- edcal.endsWith(local, "BH") ||
1380
- edcal.endsWith(local, "DJ") ||
1381
- edcal.endsWith(local, "DZ") ||
1382
- edcal.endsWith(local, "EG") ||
1383
- edcal.endsWith(local, "ER") ||
1384
- edcal.endsWith(local, "ET") ||
1385
- edcal.endsWith(local, "IQ") ||
1386
- edcal.endsWith(local, "IR") ||
1387
- edcal.endsWith(local, "JO") ||
1388
- edcal.endsWith(local, "KE") ||
1389
- edcal.endsWith(local, "KW") ||
1390
- edcal.endsWith(local, "LY") ||
1391
- edcal.endsWith(local, "MA") ||
1392
- edcal.endsWith(local, "OM") ||
1393
- edcal.endsWith(local, "QA") ||
1394
- edcal.endsWith(local, "SA") ||
1395
- edcal.endsWith(local, "SD") ||
1396
- edcal.endsWith(local, "SO") ||
1397
- edcal.endsWith(local, "TN") ||
1398
- edcal.endsWith(local, "YE")) {
1399
  /*
1400
  * Sunday
1401
  */
@@ -1420,21 +1423,21 @@ var edcal = {
1420
 
1421
  /*
1422
  * Just a little helper function to tell if a given string (str)
1423
- * ends with the given expression (expr). I could adding this
1424
  * function to the JavaScript string object, but I don't want to
1425
  * risk conflicts with other plugins.
1426
  */
1427
  endsWith: function(/*string*/ str, /*string*/ expr) {
1428
- return (str.match(expr+"$")==expr);
1429
  },
1430
-
1431
  /*
1432
  * Moves the calendar to the specified date.
1433
  */
1434
  moveTo: function(/*Date*/ date) {
1435
  edcal.isMoving = true;
1436
- jQuery("#cal").empty();
1437
-
1438
  jQuery.cookie('edcal_date', date.toString('yyyy-dd-MM'));
1439
 
1440
  /*
@@ -1442,25 +1445,25 @@ var edcal = {
1442
  the next Sunday.
1443
  */
1444
  edcal._wDate = edcal.nextStartOfWeek(date).add(-21).days();
1445
-
1446
  /*
1447
  After we remove and redo all the rows we are back to
1448
  moving in a going down direction.
1449
  */
1450
-
1451
  edcal.currentDirection = true;
1452
-
1453
  var count = edcal.weeksPref + 6;
1454
-
1455
  for (var i = 0; i < count; i++) {
1456
- edcal.createRow(jQuery("#cal"), true);
1457
  edcal._wDate.add(7).days();
1458
  }
1459
 
1460
  edcal.alignCal();
1461
-
1462
- var api = jQuery("#edcal_scrollable").scrollable();
1463
-
1464
  api.move(2);
1465
 
1466
  edcal.setDateLabel();
@@ -1474,7 +1477,7 @@ var edcal = {
1474
  save it.
1475
  */
1476
  savePosition: function() {
1477
- var cal = jQuery("#edcal_scrollable");
1478
  edcal.position = {
1479
  top: cal.offset().top,
1480
  bottom: cal.offset().top + cal.height()
@@ -1487,32 +1490,32 @@ var edcal = {
1487
  on the width of a day in the calendar and not anything in a style.
1488
  That works well for the posts in the calendar, but it means we need
1489
  to dynamically determine the width of the post when dragging.
1490
-
1491
  This value will remain the same until the calendar resizes. That is
1492
  why we do it here. We need to get the width of the first visible day
1493
  in the calendar which is why we use the complicated selector. We also
1494
  need to generate a style for it since the drag element doesn't exist
1495
  yet and using the live function would really slow down the drag operation.
1496
-
1497
  We base this on the width of a way since they might not have any posts
1498
  yet.
1499
  */
1500
  jQuery('#edcal_poststyle').remove();
1501
-
1502
  /*
1503
  We need to figure out the height of each post list. They all have the same
1504
  height so we just look at the first visible list and set some styles on the
1505
  page to set the post list height based on that. We reset the value every
1506
  time the page refreshes.
1507
  */
1508
- var dayHeight = jQuery(".rowcont:eq(2) .dayobj:first").height() - jQuery(".rowcont:eq(2) .daylabel:first").height() - 6;
1509
-
1510
- jQuery('head').append('<style id="edcal_poststyle" type="text/css">.ui-draggable-dragging {' +
1511
- 'width: ' + (jQuery(".rowcont:eq(2) .day:first").width() - 5) + 'px;' +
1512
- '}' +
1513
- '.postlist {' +
1514
- 'height: ' + dayHeight + 'px;' +
1515
- '}' +
1516
  '</style>');
1517
  },
1518
 
@@ -1539,7 +1542,7 @@ var edcal = {
1539
  * Sends no feedback and hides the section
1540
  */
1541
  noFeedback: function() {
1542
- jQuery('#feedbacksection').hide("fast");
1543
  edcal.saveFeedbackPref();
1544
  },
1545
 
@@ -1547,37 +1550,37 @@ var edcal = {
1547
  * Saves the feedback preference to the server
1548
  */
1549
  saveFeedbackPref: function() {
1550
- var url = edcal.ajax_url() + "&action=edcal_saveoptions&dofeedback=" + encodeURIComponent('done');
1551
-
1552
- jQuery.ajax( {
1553
  url: url,
1554
- type: "POST",
1555
  processData: false,
1556
  timeout: 100000,
1557
- dataType: "text",
1558
  success: function(res) {
1559
  jQuery('#feedbacksection').html(edcal.str_feedbackdone);
1560
  setTimeout(function() {
1561
- jQuery('#feedbacksection').hide("slow");
1562
  }, 5000);
1563
  },
1564
  error: function(xhr) {
1565
  edcal.showError(edcal.general_error);
1566
  if (xhr.responseText) {
1567
- edcal.output("saveOptions xhr.responseText: " + xhr.responseText);
1568
  }
1569
  }
1570
  });
1571
 
1572
  },
1573
-
1574
  /*
1575
  * Initializes the calendar
1576
  */
1577
  init: function() {
1578
- if (jQuery("#edcal_scrollable").length === 0) {
1579
  /*
1580
- * This means we are on a page without the editorial
1581
  * calendar
1582
  */
1583
  return;
@@ -1585,16 +1588,16 @@ var edcal = {
1585
 
1586
  edcal.addFeedbackSection();
1587
 
1588
- jQuery("#loading").hide();
1589
-
1590
- jQuery("#edcal_scrollable").css("height", edcal.getCalHeight() + "px");
1591
  edcal.windowHeight = jQuery(window).height();
1592
-
1593
  /*
1594
  * Add the days of the week
1595
- */
1596
  edcal.createDaysHeader();
1597
-
1598
  /*
1599
  * We start by initializting the scrollable. We use this to manage the
1600
  * scrolling of the calendar, but don't actually call it to animate the
@@ -1603,17 +1606,17 @@ var edcal = {
1603
  *
1604
  * This doesn't really change anything since the animation happens offscreen.
1605
  */
1606
- jQuery("#edcal_scrollable").scrollable({
1607
- vertical:true,
1608
  size: edcal.weeksPref,
1609
  keyboardSteps: 1,
1610
  speed: 100,
1611
- easing: "linear"
1612
- // use mousewheel plugin
1613
  }).mousewheel();
1614
-
1615
- var api = jQuery("#edcal_scrollable").scrollable();
1616
-
1617
  /*
1618
  When the user moves the calendar around we remember their
1619
  date and save it in a cookie. Then we read the cookie back
@@ -1621,22 +1624,22 @@ var edcal = {
1621
  it last.
1622
  */
1623
  var curDate = jQuery.cookie('edcal_date');
1624
-
1625
  if (curDate) {
1626
  curDate = Date.parseExact(curDate, 'yyyy-dd-MM');
1627
  edcal.output('Resetting to date from the edcal_Date cookie: ' + curDate);
1628
  } else {
1629
  curDate = Date.today();
1630
  }
1631
-
1632
  edcal.moveTo(curDate.clone());
1633
 
1634
  /*
1635
- * The scrollable handles some basic binding. This gets us
1636
- * up arrow, down arrow and the mouse wheel.
1637
  */
1638
- api.onBeforeSeek(function(evt, direction) {
1639
- // inside callbacks the "this" variable is a reference to the API
1640
  /*
1641
  * Some times for reasons I haven't been able to figure out
1642
  * the direction is an int instead of a boolean. I don't
@@ -1647,29 +1650,29 @@ var edcal = {
1647
  } else if (direction === 3) {
1648
  direction = true;
1649
  }
1650
-
1651
  if (!edcal.isMoving) {
1652
  edcal.move(1, direction);
1653
  }
1654
-
1655
  return false;
1656
  });
1657
 
1658
  /*
1659
  * We also want to listen for a few other key events
1660
  */
1661
- jQuery(document).bind("keydown", function(evt) {
1662
  //if (evt.altKey || evt.ctrlKey) { return; }
1663
  //output("evt.altKey: " + evt.altKey);
1664
  //output("evt.keyCode: " + evt.keyCode);
1665
  //output("evt.ctrlKey: " + evt.ctrlKey);
1666
-
1667
  if ((evt.keyCode === 34 && !(evt.altKey || evt.ctrlKey)) || //page down
1668
- evt.keyCode === 40 && evt.ctrlKey){ // Ctrl+down down arrow
1669
  edcal.move(edcal.weeksPref, true);
1670
  return false;
1671
  } else if ((evt.keyCode === 33 && !(evt.altKey || evt.ctrlKey)) || //page up
1672
- evt.keyCode === 38 && evt.ctrlKey){ // Ctrl+up up arrow
1673
  edcal.move(edcal.weeksPref, false);
1674
  return false;
1675
  } else if (evt.keyCode === 27) { //escape key
@@ -1677,54 +1680,57 @@ var edcal = {
1677
  return false;
1678
  }
1679
  });
1680
-
1681
- edcal.getPosts(edcal.nextStartOfWeek(curDate).add(-3).weeks(),
1682
  edcal.nextStartOfWeek(curDate).add(edcal.weeksPref + 3).weeks());
1683
-
1684
  /*
1685
  Now we bind the listeners for all of our links and the window
1686
  resize.
1687
  */
1688
- jQuery("#moveToToday").click(function() {
1689
  edcal.moveTo(Date.today());
1690
- edcal.getPosts(edcal.nextStartOfWeek(Date.today()).add(-3).weeks(),
1691
  edcal.nextStartOfWeek(Date.today()).add(edcal.weeksPref + 3).weeks());
1692
  return false;
1693
  });
1694
-
1695
- jQuery("#prevmonth").click(function() {
1696
  edcal.move(edcal.weeksPref, false);
1697
  return false;
1698
  });
1699
-
1700
- jQuery("#nextmonth").click(function() {
1701
  edcal.move(edcal.weeksPref, true);
1702
  return false;
1703
  });
1704
-
1705
  function resizeWindow(e) {
1706
  if (edcal.windowHeight != jQuery(window).height()) {
1707
- jQuery("#edcal_scrollable").css("height", edcal.getCalHeight() + "px");
1708
  edcal.windowHeight = jQuery(window).height();
1709
  edcal.savePosition();
1710
  }
1711
  }
1712
- jQuery(window).bind("resize", resizeWindow);
1713
 
1714
- jQuery("#newPostScheduleButton").live("click", function(evt) {
1715
  // if the button is disabled, don't do anything
1716
- if( jQuery(this).hasClass('disabled') ) {
1717
  return false;
1718
  }
1719
- // Otherwise, save the post
 
 
 
1720
  return edcal.savePost(null, false, true);
1721
  });
1722
 
1723
- jQuery("#edcal-title-new-field").bind("keyup", function(evt) {
1724
- if (jQuery("#edcal-title-new-field").val().length > 0 && jQuery('#edcal-time').val().length > 0) {
1725
- jQuery("#newPostScheduleButton").removeClass("disabled");
1726
  } else {
1727
- jQuery("#newPostScheduleButton").addClass("disabled");
1728
  }
1729
 
1730
  if (evt.keyCode == 13) { // enter key
@@ -1734,18 +1740,18 @@ var edcal = {
1734
  return edcal.savePost(null, true);
1735
  }
1736
  });
1737
-
1738
- jQuery("#edcal-status").bind("change", function(evt) {
1739
  edcal.updatePublishButton();
1740
  });
1741
 
1742
- jQuery("#edcal_weeks_pref").live("keyup", function(evt) {
1743
- if (jQuery("#edcal_weeks_pref").val().length > 0) {
1744
- jQuery("#edcal_applyoptions").removeClass("disabled");
1745
  } else {
1746
- jQuery("#edcal_applyoptions").addClass("disabled");
1747
  }
1748
-
1749
  if (evt.keyCode == 13) { // enter key
1750
  edcal.saveOptions();
1751
  }
@@ -1753,16 +1759,16 @@ var edcal = {
1753
  });
1754
 
1755
  edcal.savePosition();
1756
-
1757
  edcal.addOptionsSection();
1758
-
1759
  jQuery('#edcal-time').timePicker({
1760
  show24Hours: edcal.timeFormat === 'H:i',
1761
- separator:':',
1762
  step: 30
1763
  });
1764
  },
1765
-
1766
  /*
1767
  This function updates the text of te publish button in the quick
1768
  edit dialog to match the current operation.
@@ -1785,25 +1791,25 @@ var edcal = {
1785
  edcal.output('Changing the date of "' + post.title + '" to ' + newdate);
1786
  var newdateFormatted = edcal.getDayFromDayId(newdate).toString(edcal.wp_dateFormat);
1787
 
1788
- var url = edcal.ajax_url() + "&action=edcal_changedate&postid=" + post.id +
1789
- "&postStatus=" + post.status +
1790
- "&newdate=" + newdateFormatted + "&olddate=" + edcal.getDayFromDayId(post.date).toString(edcal.wp_dateFormat);
 
 
1791
 
1792
- jQuery("#post-" + post.id).addClass("loadingclass");
1793
-
1794
- jQuery.ajax( {
1795
  url: url,
1796
- type: "POST",
1797
  processData: false,
1798
  timeout: 100000,
1799
- dataType: "json",
1800
  success: function(res) {
1801
  if (res.error) {
1802
  /*
1803
  * If there was an error we need to remove the dropped
1804
  * post item.
1805
  */
1806
- edcal.removePostItem(newdate, "post-" + res.post.id);
1807
  if (res.error === edcal.CONCURRENCY_ERROR) {
1808
  edcal.displayMessage(edcal.concurrency_error + '<br />' + res.post.title);
1809
  } else if (res.error === edcal.PERMISSION_ERROR) {
@@ -1811,9 +1817,9 @@ var edcal = {
1811
  } else if (res.error === edcal.NONCE_ERROR) {
1812
  edcal.displayMessage(edcal.checksum_error);
1813
  }
1814
- }
1815
 
1816
- edcal.removePostItem(res.post.date, "post-" + res.post.id);
1817
  edcal.addPostItem(res.post, res.post.date);
1818
  edcal.addPostItemDragAndToolltip(res.post.date);
1819
 
@@ -1823,24 +1829,24 @@ var edcal = {
1823
  },
1824
  error: function(xhr, textStatus, error) {
1825
  edcal.showError(edcal.general_error);
1826
-
1827
- edcal.output("textStatus: " + textStatus);
1828
- edcal.output("error: " + error);
1829
  if (xhr.responseText) {
1830
- edcal.output("changeDate xhr.responseText: " + xhr.responseText);
1831
  }
1832
  }
1833
  });
1834
 
1835
  },
1836
-
1837
  /*
1838
  Makes an AJAX call to get the posts from the server within the
1839
  specified dates.
1840
  */
1841
  getPosts: function(/*Date*/ from, /*Date*/ to, /*function*/ callback) {
1842
- edcal.output("Getting posts from " + from + " to " + to);
1843
-
1844
  var shouldGet = edcal.cacheDates[from];
1845
 
1846
  if (shouldGet) {
@@ -1849,8 +1855,8 @@ var edcal = {
1849
  * that we have already covered. This is cutting down on
1850
  * it somewhat, but we could get much better about this.
1851
  */
1852
- edcal.output("Using cached results for posts from " + from.toString("dd-MMM-yyyy") + " to " + to.toString("dd-MMM-yyyy"));
1853
-
1854
  if (callback) {
1855
  callback();
1856
  }
@@ -1859,25 +1865,29 @@ var edcal = {
1859
 
1860
  edcal.cacheDates[from] = true;
1861
 
1862
- var url = edcal.ajax_url() + "&action=edcal_posts&from=" + from.toString("yyyy-MM-dd") + "&to=" + to.toString("yyyy-MM-dd");
1863
-
1864
- jQuery("#loading").show();
 
 
1865
 
1866
- jQuery.ajax( {
 
 
1867
  url: url,
1868
- type: "GET",
1869
  processData: false,
1870
  timeout: 100000,
1871
- dataType: "text",
1872
  success: function(res) {
1873
- jQuery("#loading").hide();
1874
  /*
1875
  * These result here can get pretty large on a busy blog and
1876
  * the JSON parser from JSON.org works faster than the native
1877
  * one used by JQuery.
1878
  */
1879
  var parsedRes = JSON.parseIt(res);
1880
-
1881
  if (parsedRes.error) {
1882
  /*
1883
  * If there was an error we need to remove the dropped
@@ -1889,7 +1899,7 @@ var edcal = {
1889
  return;
1890
  }
1891
  var postDates = [];
1892
-
1893
  /*
1894
  We get the posts back with the most recent post first. That
1895
  is what most blogs want. However, we want them in the other
@@ -1909,8 +1919,8 @@ var edcal = {
1909
  * case to make sure we don't get into trouble.
1910
  */
1911
  post.date = post.date.replace(post.date.substring(2, 3), post.date.substring(2, 3).toUpperCase());
1912
-
1913
- edcal.removePostItem(post.date, "post-" + post.id);
1914
  edcal.addPostItem(post, post.date);
1915
  postDates[postDates.length] = post.date;
1916
  }
@@ -1918,8 +1928,8 @@ var edcal = {
1918
 
1919
  /*
1920
  * If the blog has a very larger number of posts then adding
1921
- * them all can make the UI a little slow. Particularly IE
1922
- * pops up a warning giving the user a chance to abort the
1923
  * script. Adding tooltips and making the items draggable is
1924
  * a lot of what makes things slow. Delaying those two operations
1925
  * makes the UI show up much faster and the user has to wait
@@ -1927,54 +1937,58 @@ var edcal = {
1927
  * stop complaining.
1928
  */
1929
  setTimeout(function() {
1930
- edcal.output("Finished adding draggable support to " + postDates.length + " posts.");
1931
  jQuery.each(postDates, function(i, postDate) {
1932
  edcal.addPostItemDragAndToolltip(postDate);
1933
  });
1934
  }, 300);
1935
-
1936
  if (callback) {
1937
  callback(res);
1938
  }
1939
-
1940
  },
1941
  error: function(xhr) {
1942
  edcal.showError(edcal.general_error);
1943
  if (xhr.responseText) {
1944
- edcal.output("getPosts xhr.responseText: " + xhr.responseText);
1945
  }
1946
  }
1947
  });
1948
  },
1949
-
1950
  /*
1951
  * Retreives a single post item based on the id
1952
  * Can optionally pass a callback function that is triggered
1953
- * when the call successfully completes. The post object is passed
1954
  * as a parameter for the callback.
1955
  */
1956
  getPost: function(/*int*/ postid, /*function*/ callback) {
1957
-
1958
  if (postid === 0) {
1959
  return false;
1960
  }
1961
-
1962
  // show loading
1963
- jQuery("#loading").show();
1964
-
1965
- var url = edcal.ajax_url() + "&action=edcal_getpost&postid=" + postid;
1966
-
1967
- jQuery.ajax( {
 
 
 
 
1968
  url: url,
1969
- type: "GET",
1970
  processData: false,
1971
  timeout: 100000,
1972
- dataType: "json",
1973
  success: function(res) {
1974
  // hide loading
1975
- jQuery("#loading").hide();
1976
-
1977
- edcal.output("xhr for getPost returned: " + res);
1978
  if (res.error) {
1979
  if (res.error === edcal.NONCE_ERROR) {
1980
  edcal.showError(edcal.checksum_error);
@@ -1988,17 +2002,17 @@ var edcal = {
1988
  },
1989
  error: function(xhr) {
1990
  // hide loading
1991
- jQuery("#loading").hide();
1992
-
1993
  edcal.showError(edcal.general_error);
1994
  if (xhr.responseText) {
1995
- edcal.output("getPost xhr.responseText: " + xhr.responseText);
1996
  }
1997
  return false;
1998
  }
1999
  });
2000
  },
2001
-
2002
  /*
2003
  This function adds the scren options tab to the top of the screen. I wish
2004
  WordPress had a hook so I could provide this in PHP, but as of version 2.9.1
@@ -2006,18 +2020,18 @@ var edcal = {
2006
  doing this in JavaScript.
2007
  */
2008
  addOptionsSection: function() {
2009
- var html =
2010
- '<div class="hide-if-no-js screen-meta-toggle" id="screen-options-link-wrap">' +
2011
- '<a class="show-settings" ' +
2012
- 'id="show-edcal-settings-link" ' +
2013
- 'onclick="edcal.toggleOptions(); return false;" ' +
2014
- 'href="#" ' +
2015
- 'style="background-image: url(images/screen-options-right.gif);">' + edcal.str_screenoptions + '</a>' +
2016
  '</div>';
2017
-
2018
- jQuery("#screen-meta-links").append(html);
2019
  },
2020
-
2021
  /*
2022
  Respond to clicks on the Screen Options tab by sliding it down when it
2023
  is up and sliding it up when it is down.
@@ -2027,32 +2041,32 @@ var edcal = {
2027
  /*
2028
  Show the screen options section. We start by saving off the old HTML
2029
  */
2030
- edcal.helpMeta = jQuery("#contextual-help-wrap").html();
2031
 
2032
  /*
2033
  * Set up the visible fields option
2034
  */
2035
  var optionsHtml = '<div class="metabox-prefs" id="calendar-fields-prefs">' +
2036
- '<h5>' + edcal.str_show_opts + '</h5>' +
2037
- '<label for="author-hide">' +
2038
  '<input type="checkbox" ' + edcal.isPrefChecked(edcal.authorPref) + 'value="true" id="author-hide" ' +
2039
- 'name="author-hide" class="hide-column-tog" />' + edcal.str_opt_author +
2040
- '</label>' +
2041
- '<label for="status-hide">' +
2042
  '<input type="checkbox" ' + edcal.isPrefChecked(edcal.statusPref) + 'value="true" id="status-hide" ' +
2043
- 'name="status-hide" class="hide-column-tog" />' + edcal.str_opt_status +
2044
- '</label>' +
2045
- '<label for="time-hide">' +
2046
- '<input type="checkbox" ' + edcal.isPrefChecked(edcal.timePref) + 'value="true" id="time-hide" ' +
2047
- 'name="time-hide" class="hide-column-tog" />' + edcal.str_opt_time +
2048
- '</label>' +
2049
  '</div>';
2050
-
2051
  /*
2052
  * Set up the number of posts option
2053
  */
2054
- optionsHtml += '<div class="metabox-prefs">' +
2055
- '<h5>' + edcal.str_show_title + '</h5>' +
2056
  '<select id="edcal_weeks_pref" ' + 'class="screen-per-page" title="' + edcal.str_weekstt + '"> ';
2057
 
2058
  var weeks = parseInt(edcal.weeksPref, 10);
@@ -2064,10 +2078,10 @@ var edcal = {
2064
  }
2065
  }
2066
 
2067
- optionsHtml += '</select>' +
2068
- edcal.str_opt_weeks +
2069
  '</div>';
2070
-
2071
  /*
2072
  I started work on adding a color picker so you could choose the color for
2073
  drafts, published posts, and scheduled posts. However, that makes the settings
@@ -2075,69 +2089,69 @@ var edcal = {
2075
  */
2076
  //optionsHtml += '<h5>' + edcal.str_optionscolors + '</h5>';
2077
  //optionsHtml += edcal.generateColorPicker(edcal.str_optionsdraftcolor, 'draft-color', 'lightgreen');
2078
-
2079
-
2080
  optionsHtml += '<br /><button id="edcal_applyoptions" onclick="edcal.saveOptions(); return false;" class="save button">' + edcal.str_apply + '</button>';
2081
-
2082
- jQuery("#contextual-help-wrap").html(optionsHtml);
2083
-
2084
- jQuery("#contextual-help-link-wrap").css('visibility', 'hidden');
2085
-
2086
  jQuery('#contextual-help-wrap').slideDown('normal');
2087
-
2088
- jQuery("#show-edcal-settings-link").css("background-image", "url(images/screen-options-right-up.gif)");
2089
  } else {
2090
  jQuery('#contextual-help-wrap').slideUp('fast');
2091
-
2092
  /*
2093
  * restore the old HTML
2094
  */
2095
- jQuery("#contextual-help-wrap").html(edcal.helpMeta);
2096
-
2097
  edcal.helpMeta = null;
2098
-
2099
- jQuery("#show-edcal-settings-link").css("background-image", "url(images/screen-options-right.gif)");
2100
- jQuery("#contextual-help-link-wrap").css('visibility', '');
2101
  }
2102
  },
2103
-
2104
  generateColorPicker: function(/*String*/ title, /*string*/ id, /*string*/ value) {
2105
  var html = '<div id="' + id + '" class="optionscolorrow">';
2106
-
2107
  html += '<span style="background-color: ' + value + ';" class="colorlabel"> ' + title + '</span> ';
2108
-
2109
- var colors = [ "lightred", "orange", "yellow", "lightgreen", "lightblue", "purple", "lightgray" ];
2110
-
2111
- edcal.output("colors.length: " + colors.length);
2112
  for (var i = 0; i < colors.length; i++) {
2113
  html += '<a href="#" class="optionscolor ';
2114
-
2115
  if (colors[i] === value) {
2116
  html += 'colorselected';
2117
-
2118
  }
2119
-
2120
- html += '" class=' + id + colors[i] + '" style="background-color: ' + colors[i] + '; left: ' + ((i * 20) + 50) + 'px" ' +
2121
  'onclick="edcal.selectColor(\'' + id + '\', \'' + colors[i] + '\'); return false;"></a>';
2122
-
2123
  }
2124
-
2125
  html += '</div>';
2126
-
2127
  return html;
2128
-
2129
  },
2130
-
2131
  selectColor: function(/*string*/ id, /*string*/ value) {
2132
- edcal.output("selectColor(" + id + ", " + value + ")");
2133
  jQuery('#' + id + ' .colorlabel').css('background-color', value);
2134
-
2135
  jQuery('#' + id + ' .colorselected').removeClass('colorselected');
2136
-
2137
  jQuery('#' + id + 'value').addClass('colorselected');
2138
-
2139
  },
2140
-
2141
  isPrefChecked: function(/*boolean*/ prefVal) {
2142
  if (prefVal) {
2143
  return ' checked="checked" ';
@@ -2145,7 +2159,7 @@ var edcal = {
2145
  return '';
2146
  }
2147
  },
2148
-
2149
  /*
2150
  Save the number of weeks options with an AJAX call. This happens
2151
  when you press the apply button.
@@ -2155,28 +2169,28 @@ var edcal = {
2155
  We start by validating the number of weeks. We only allow
2156
  1, 2, 3, 4, or 5 weeks at a time.
2157
  */
2158
- if (jQuery("#edcal_weeks_pref").val() !== '1' &&
2159
- jQuery("#edcal_weeks_pref").val() !== '2' &&
2160
- jQuery("#edcal_weeks_pref").val() !== '3' &&
2161
- jQuery("#edcal_weeks_pref").val() !== '4' &&
2162
- jQuery("#edcal_weeks_pref").val() !== '5') {
2163
  humanMsg.displayMsg(edcal.str_weekserror);
2164
  return;
2165
  }
2166
-
2167
- var url = edcal.ajax_url() + "&action=edcal_saveoptions&weeks=" +
2168
- encodeURIComponent(jQuery("#edcal_weeks_pref").val());
2169
-
2170
  jQuery('#calendar-fields-prefs').find('input, textarea, select').each(function() {
2171
  url += '&' + encodeURIComponent(this.name) + '=' + encodeURIComponent(this.checked);
2172
  });
2173
-
2174
- jQuery.ajax( {
2175
  url: url,
2176
- type: "POST",
2177
  processData: false,
2178
  timeout: 100000,
2179
- dataType: "text",
2180
  success: function(res) {
2181
  /*
2182
  Now we refresh the page because I'm too lazy to
@@ -2187,25 +2201,25 @@ var edcal = {
2187
  error: function(xhr) {
2188
  edcal.showError(edcal.general_error);
2189
  if (xhr.responseText) {
2190
- edcal.output("saveOptions xhr.responseText: " + xhr.responseText);
2191
  }
2192
  }
2193
  });
2194
  },
2195
-
2196
  /**
2197
  * Outputs info messages to the Firebug console if it is available.
2198
- *
2199
- * @param msg the message to write
2200
  */
2201
  output: function(msg) {
2202
  if (window.console) {
2203
  console.info(msg);
2204
  }
2205
  },
2206
-
2207
  /*
2208
- * Shows an error message and sends the message as an error to the
2209
  * Firebug console if it is available.
2210
  */
2211
  showError: function(/*string*/ msg) {
@@ -2214,7 +2228,7 @@ var edcal = {
2214
  }
2215
 
2216
  edcal.displayMessage(msg);
2217
-
2218
  },
2219
 
2220
  /*
@@ -2223,7 +2237,7 @@ var edcal = {
2223
  displayMessage: function(/*string*/ msg) {
2224
  humanMsg.displayMsg(msg);
2225
  },
2226
-
2227
  /*
2228
  * A helper function to get the parameters from the
2229
  * current URL.
@@ -2239,29 +2253,33 @@ var edcal = {
2239
 
2240
  return vars;
2241
  },
2242
-
2243
  /*
2244
  * Show an error indicating the calendar couldn't be loaded
2245
  */
2246
  showFatalError: function(message) {
2247
- jQuery("#edcal_main_title").after(
2248
- '<div class="updated below-h2" id="message"><p>' +
2249
- edcal.str_fatal_error + message + '<br></p></div>');
 
 
 
 
2250
  }
2251
  };
2252
 
2253
  /*
2254
  * Helper function for jQuery to center a div
2255
  */
2256
- jQuery.fn.center = function () {
2257
- this.css("position","absolute");
2258
- this.css("top", ( jQuery(window).height() - this.outerHeight() ) / 2+jQuery(window).scrollTop() + "px");
2259
- this.css("left", ( jQuery(window).width() - this.outerWidth() ) / 2+jQuery(window).scrollLeft() + "px");
2260
  return this;
2261
  };
2262
 
2263
 
2264
- jQuery(document).ready(function(){
2265
  try {
2266
  edcal.init();
2267
  } catch (e) {
13
  * limitations under the License.
14
  *
15
  ******************************************************************************/
16
+
17
  /*
18
  This is the WordPress editorial calendar. It is a continuous
19
  calendar in both directions. That means instead of showing only
21
  can scroll from one month to the next using the up and down
22
  arrow keys, the page up and page down keys, the next and previous
23
  month buttons, and their mouse wheel.
24
+
25
  The calendar shows five weeks visible at a time and maintains 11
26
  weeks of rendered HTML. Only the middle weeks are visible.
27
+
28
  Week 1
29
  Week 2
30
  Week 3
36
  Week 9
37
  Week 10
38
  Week 11
39
+
40
  When the user scrolls down one week the new week is added at the
41
  end of the calendar and the first week is removed. In this way
42
  the calendar will only ever have 11 weeks total and won't use up
43
  excessive memory.
44
+
45
  This calendar uses AJAX to call into the functions defined in
46
  edcal.php. These functions get posts and change post dates.
47
+
48
  The HTML structure of the calendar is:
49
+
50
  <div id="cal">
51
  <div id="row08Nov2009">
52
  <div id="row08Nov2009row">
62
  </div>
63
  */
64
  var edcal = {
65
+
66
  /*
67
  This value is the number of weeks the user wants to see at one time
68
  in the calendar.
69
  */
70
  weeksPref: 3,
71
+
72
  /*
73
  This is a preference value indicating if you see the post status
74
  */
88
  This is a preference value indicating if we should prompt for feeback
89
  */
90
  doFeedbackPref: true,
91
+
92
  /*
93
  * True if the calendar is in the process of moving
94
  */
98
  * True if we are in the middle of dragging a post
99
  */
100
  inDrag: false,
101
+
102
  /*
103
  True if the calendar is in the process of queueing scrolling
104
  during a drag.
106
  isDragScrolling: false,
107
 
108
  /*
109
+ * This is the format we use to dates that we use as IDs in the
110
  * calendar. It is independant of the visible date which is
111
  * formatted based on the user's locale.
112
  */
113
  internalDateFormat: 'ddMMyyyy',
114
+
115
  /*
116
+ This is the position of the calendar on the screen in pixels.
117
  It is an array with two fields: top and bottom.
118
  */
119
  position: null,
127
  * This is the first day of the next month
128
  */
129
  firstDayOfNextMonth: null,
130
+
131
  /*
132
  * The date format used by wordpress
133
  */
134
+ wp_dateFormat: 'yyyy-MM-dd',
135
+
136
  /*
137
  * The cache of dates we have already loaded posts for.
138
  */
139
+ cacheDates: [],
140
+
141
  /*
142
  * The ID of the timer we use to batch new post requests
143
  */
144
  tID: null,
145
+
146
  /*
147
  * The number of steps moving for this timer.
148
  */
162
  * The constant for the nonce error
163
  */
164
  NONCE_ERROR: 6,
165
+
166
  /*
167
  The direction the calendar last moved.
168
  true = down = to the future
170
 
171
  */
172
  currentDirection: true,
173
+
174
  /*
175
  This date is our index. When the calendar moves we
176
  update this date to indicate the next rows we need
177
  to add.
178
  */
179
  _wDate: Date.today(),
180
+
181
  /*
182
  * The date since the previous move
183
  */
186
  /*
187
  * This is a number from 0-6 indicating when the start
188
  * of the week is. The user sets this in the Settings >
189
+ * General page and it is a single value for the entire
190
  * server. We are setting this value in edcal.php
191
  */
192
  startOfWeek: null,
193
+
194
  /*
195
  A cache of all the posts we have loaded so far. The
196
  data structure is:
197
+
198
  posts [date - ddMMMyyyy][posts array - post object from JSON data]
199
  */
200
+ posts: [],
201
+
202
  /*
203
  IE will sometimes fire the resize event twice for the same resize
204
  action. We save it so we only resize the calendar once and avoid
205
  any flickering.
206
  */
207
  windowHeight: 0,
208
+
209
  /*
210
  This function aligns the grid in two directions. There
211
  is a vertical grid with a row of each week and a horizontal
216
  var y = 0;
217
  var count = 1;
218
 
219
+ jQuery(gridid).each(function() {
220
+ jQuery(this).css('position', 'relative');
221
+
222
+ jQuery(this).children('div').each(function() {
223
  jQuery(this).css({
224
+ width: cellWidth + '%',
225
+ height: cellHeight + '%',
226
+ position: 'absolute',
227
+ left: x + '%',
228
+ top: y + '%'
229
  });
230
+
231
  if ((count % cols) === 0) {
232
  x = 0;
233
  y += cellHeight + padding;
234
  } else {
235
  x += cellWidth + padding;
236
  }
237
+
238
  count++;
239
  });
240
  });
241
  },
242
+
243
  /*
244
  This is a helper function to align the calendar so we don't
245
  have to change the cell sizes in multiple places.
246
  */
247
  alignCal: function() {
248
+ edcal.alignGrid('#cal', 1, 100, (100 / edcal.weeksPref) - 1, 1);
249
  },
250
 
251
+
252
  /*
253
  This function creates the days header at the top of the
254
  calendar.
255
  */
256
  createDaysHeader: function() {
257
  /*
258
+ * The first day of the week in the calendar depends on
259
  * a wordpress setting and maybe the server locale. This
260
  * means we need to determine the days of the week dynamically.
261
  * Luckily the Date.js library already has these strings
266
  var date = Date.today().next().sunday();
267
 
268
  /*
269
+ * We need to call nextStartOfWeek to make sure the
270
  * edcal.startOfWeek variable gets initialized.
271
  */
272
  edcal.nextStartOfWeek(date);
 
273
 
274
+
275
+ var html = '<div class="dayheadcont"><div class="dayhead firstday">' +
276
+ date.add(edcal.startOfWeek).days().toString('dddd') +
277
  '</div>';
278
 
279
  html += '<div class="dayhead">' + date.add(1).days().toString('dddd') + '</div>';
282
  html += '<div class="dayhead">' + date.add(1).days().toString('dddd') + '</div>';
283
  html += '<div class="dayhead">' + date.add(1).days().toString('dddd') + '</div>';
284
  html += '<div class="dayhead lastday">' + date.add(1).days().toString('dddd') + '</div>';
285
+
286
+ jQuery('#cal_cont').prepend(html);
287
+
288
+ edcal.alignGrid('.dayheadcont', 7, 13.8, 100, 0.5);
289
  },
290
 
291
  /*
302
  /*
303
  * Date is before today
304
  */
305
+ daystyle = 'beforeToday';
306
  } else {
307
  /*
308
  * Date is after today
309
  */
310
+ daystyle = 'todayAndAfter';
311
  }
312
  if (!edcal.firstDayOfMonth) {
313
  /*
314
+ * We only need to figure out the first and last day
315
  * of the month once
316
  */
317
  edcal.firstDayOfMonth = Date.today().moveToFirstDayOfMonth().clearTime();
319
  }
320
  if (date.between(edcal.firstDayOfMonth, edcal.firstDayOfNextMonth)) {
321
  /*
322
+ * If the date isn't before the first of the
323
+ * month and it isn't after the last of the
324
  * month then it is in the current month.
325
  */
326
+ monthstyle = 'month-present';
327
  } else if (date.compareTo(edcal.firstDayOfMonth) == 1) {
328
  /*
329
  * Then the date is after the current month
330
  */
331
+ monthstyle = 'month-future';
332
  } else if (date.compareTo(edcal.firstDayOfNextMonth) == -1) {
333
  /*
334
  * Then the date is before the current month
335
  */
336
+ monthstyle = 'month-past';
337
  }
338
+
339
+ if (date.toString('dd') == '01') {
340
  /*
341
  * This this date is the first day of the month
342
  */
343
  daystyle += ' firstOfMonth';
344
  }
345
+
346
+
347
+ return monthstyle + ' ' + daystyle;
348
  },
349
 
350
  /*
355
  if (edcal.inDrag) {
356
  return;
357
  }
358
+
359
+ var createLink = jQuery('#' + dayid + ' a.daynewlink');
360
+ createLink.css('display', 'block');
361
  createLink.bind('click', edcal.addPost);
362
  },
363
 
366
  outside of the calendar day.
367
  */
368
  hideAddPostLink: function(/*string*/ dayid) {
369
+ var link = jQuery('#' + dayid + ' a.daynewlink').hide();
370
  link.unbind('click', edcal.addPost);
371
  },
372
+
373
  /*
374
  Creates a row of the calendar and adds all of the CSS classes
375
  and listeners for each calendar day.
376
  */
377
  createRow: function(/*jQuery*/ parent, /*bool*/ append) {
378
  var _date = edcal._wDate.clone();
379
+
380
+ var newrow = '<div class="rowcont" id="' + 'row' + edcal._wDate.toString(edcal.internalDateFormat) + '">' +
381
  '<div id="' + 'row' + edcal._wDate.toString(edcal.internalDateFormat) + 'row" class="row">';
382
  for (var i = 0; i < 7; i++) {
383
  /*
385
  * could do this with the JQuery live function, but there are a lot
386
  * of days in the calendar and the live function gets a little slow.
387
  */
388
+ newrow += '<div onmouseover="edcal.showAddPostLink(\'' + _date.toString(edcal.internalDateFormat) + '\');" ' +
389
+ 'onmouseout="edcal.hideAddPostLink(\'' + _date.toString(edcal.internalDateFormat) + '\');" ' +
390
+ 'id="' + _date.toString(edcal.internalDateFormat) + '" class="day ' +
391
+ edcal.getDateClass(_date) + ' ' +
392
+ _date.toString('dddd').toLowerCase() + ' month-' +
393
+ _date.toString('MM').toLowerCase() + '">';
394
+
395
  newrow += '<div class="dayobj">';
396
+
397
+ newrow += '<a href="#" adddate="' + _date.toString('MMMM d') + '" class="daynewlink" title="' + edcal.str_newpost + _date.toString('MMMM d') + '" ' +
398
  'onclick="return false;">' + edcal.str_addPostLink + '</a>';
399
+
400
+ if (_date.toString('dd') == '01') {
401
+ newrow += '<div class="daylabel">' + _date.toString('MMM d');
402
  } else {
403
+ newrow += '<div class="daylabel">' + _date.toString('d');
404
  }
405
+
406
+
407
  newrow += '</div>';
408
 
409
  newrow += '<ul class="postlist">';
410
 
411
  newrow += edcal.getPostItems(_date.toString(edcal.internalDateFormat));
412
+
413
  newrow += '</ul>';
414
+
415
  newrow += '</div>';
416
  newrow += '</div>';
417
  _date.add(1).days();
418
  }
419
+
420
  newrow += '</div></div>';
421
+
422
  if (append) {
423
  parent.append(newrow);
424
+
425
  } else {
426
  parent.prepend(newrow);
427
  }
428
+
429
  /*
430
  * This is the horizontal alignment of an individual week
431
  */
432
+ edcal.alignGrid('#row' + edcal._wDate.toString(edcal.internalDateFormat) + 'row', 7, 13.9, 100, 0.5);
433
+
434
  edcal.draggablePost('#row' + edcal._wDate.toString(edcal.internalDateFormat) + ' li.post');
435
 
436
  jQuery('#row' + edcal._wDate.toString(edcal.internalDateFormat) + ' > div > div.day').droppable({
443
  fragile, but it is much faster than doing date
444
  arithmetic every time the mouse twitches.
445
  */
446
+ if (jQuery(this).hasClass('beforeToday')) {
447
+ if (ui.hasClass('draft')) {
448
  return true;
449
  } else {
450
  return false;
459
  //output('dropped ui.draggable.attr("id"): ' + ui.draggable.attr("id"));
460
  //output('dropped on jQuery(this).attr("id"): ' + jQuery(this).attr("id"));
461
  //output('ui.draggable.html(): ' + ui.draggable.html());
 
 
462
 
463
+ var dayId = ui.draggable.parent().parent().parent().attr('id');
464
+
465
+ edcal.doDrop(dayId, ui.draggable.attr('id'), jQuery(this).attr('id'));
466
  }
467
  });
468
 
478
 
479
  // Step 0. Get the post object from the map
480
  var post = edcal.findPostForId(parentId, postId);
481
+
482
  // Step 1. Remove the post from the posts map
483
  edcal.removePostFromMap(parentId, postId);
484
 
485
  // Step 2. Remove the old element from the old parent.
486
  jQuery('#' + postId).remove();
487
+
488
  // Step 3. Add the item to the new DOM parent
489
  jQuery('#' + newDate + ' .postlist').append(edcal.createPostItem(post, newDate));
490
 
505
  */
506
  draggablePost: function(/*post selector*/ post) {
507
  jQuery(post).each(function() {
508
+ var postObj = edcal.findPostForId(jQuery(this).parent().parent().parent().attr('id'),
509
+ jQuery(this).attr('id'));
510
  if (edcal.isPostMovable(postObj)) {
511
+ jQuery(this).draggable({
512
  revert: 'invalid',
513
  appendTo: 'body',
514
+ helper: 'clone',
515
  distance: 1,
516
  addClasses: false,
517
  start: function() {
526
  scroll: false,
527
  refreshPositions: true
528
  });
529
+ jQuery(this).addClass('draggable');
530
  }
531
  });
532
  },
542
  }
543
 
544
  edcal.isDragScrolling = true;
545
+
546
  if (event.pageY < (edcal.position.top + 10)) {
547
  /*
548
  This means we're close enough to the top of the calendar to
568
  edcal.isDragScrolling = false;
569
  }, 300);
570
  },
571
+
572
  /*
573
  This is a utility method to find a post and remove it
574
  from the cache map.
577
  if (edcal.posts[dayobjId]) {
578
  for (var i = 0; i < edcal.posts[dayobjId].length; i++) {
579
  if (edcal.posts[dayobjId][i] &&
580
+ 'post-' + edcal.posts[dayobjId][i].id === postId) {
581
  edcal.posts[dayobjId][i] = null;
582
  return true;
583
  }
584
  }
585
  }
586
+
587
  return false;
588
  },
589
+
590
  /*
591
  * Adds a post to an already existing calendar day.
592
  */
596
  * be much more adaptable to reference the class by name, but this is
597
  * significantly faster. Especially on IE.
598
  */
599
+ jQuery('#' + dayobjId + ' > div > ul').append(edcal.createPostItem(post, dayobjId));
600
  },
601
 
602
  /*
612
  Deletes the post specified. Will only be executed once the user clicks the confirm link to proceed.
613
  */
614
  deletePost: function(/*Post ID*/ postId, /*function*/ callback) {
615
+
616
+ var url = edcal.ajax_url() + '&action=edcal_deletepost&postid=' + postId;
617
+
618
+ jQuery.ajax({
619
  url: url,
620
+ type: 'POST',
621
  processData: false,
622
  timeout: 100000,
623
+ dataType: 'json',
624
+ success: function(res) {
625
+ edcal.removePostItem(res.post.date, 'post-' + res.post.id);
626
  if (res.error) {
627
  /*
628
  * If there was an error we need to remove the dropped
642
  error: function(xhr) {
643
  edcal.showError(edcal.general_error);
644
  if (xhr.responseText) {
645
+ edcal.output('deletePost xhr.responseText: ' + xhr.responseText);
646
  }
647
  }
648
  });
657
  confirmDelete: function(/*string*/ posttitle) {
658
  if (confirm(edcal.str_del_msg1 + posttitle + edcal.str_del_msg2)) {
659
  return true;
660
+ // [wes] might be better to call deletePost from here directly, rather than return control back to the agent... which will then follow the link and call deletePost
661
  } else {
662
  return false;
663
  }
664
  },
665
+
666
  /*
667
  This is a simple function that creates the AJAX URL with the
668
  nonce value generated in edcal.php.
669
  */
670
  ajax_url: function() {
671
+ return ajaxurl + '?_wpnonce=' + edcal.wp_nonce;
672
  },
673
 
674
  /*
675
  NOT USED
676
  */
677
  getMediaBar: function() {
678
+ return jQuery('#cal_mediabar').html();
679
  },
680
+
681
  /*
682
  * Called when the "Add a post" link is clicked.
683
  * Sets up a post object and displays the add form
684
  */
685
+ addPost: function() {
686
+ jQuery('#newPostScheduleButton').addClass('disabled');
687
+
688
+ var date = jQuery(this).parent().parent().attr('id');
689
+
690
  var formattedtime = '10:00';
691
  if (edcal.timeFormat !== 'H:i') {
692
+ formattedtime += ' AM';
693
  }
694
+
695
  var post = {
696
  id: 0,
697
  date: date,
701
  edcal.showForm(post);
702
  return false;
703
  },
704
+
705
  /*
706
  * Called when the Edit link for a post is clicked.
707
  * Gets post details via an AJAX call and displays the edit form
709
  */
710
  editPost: function(/*int*/ post_id) {
711
  // Un-disable the save buttons because we're editing
712
+ jQuery('#newPostScheduleButton').removeClass('disabled');
713
+
714
  // Editing, so we need to make an ajax call to get body of post
715
  edcal.getPost(post_id, edcal.showForm);
716
  return false;
717
  },
718
+
719
+
720
  /*
721
  * When the user presses the new post link on each calendar cell they get
722
  * a tooltip which prompts them to add or edit a post. Once
723
  * they hit save we call this function.
724
+ *
725
  * post - post object containing data for the post
726
  * doEdit - should we edit the post immediately? if true we send the user
727
  * to the edit screen for their new post.
728
  */
729
  savePost: function(/*object*/ post, /*boolean*/ doEdit, /*boolean*/ doPublish, /*function*/ callback) {
730
+ if (typeof(post) === 'undefined' || post === null) {
731
  post = edcal.serializePost();
732
  }
733
+
734
+ if (!post.title || post.title === '') {
735
  return;
736
  }
 
 
737
 
738
+ edcal.output('savePost(' + post.date + ', ' + post.title + ')');
739
+
740
+ jQuery('#edit-slug-buttons').addClass('tiploading');
741
 
742
  /*
743
  The date.js library has a bug where it gives the wrong
745
  but we still need to work aorund the issue. Hackito
746
  ergo sum.
747
  */
748
+ if (post.time.toUpperCase() === '12:00 PM') {
749
+ post.time = '12:00';
750
+ } else if (post.time.toUpperCase() === '12:30 PM') {
751
+ post.time = '12:30';
752
+ } else if (post.time.toUpperCase() === '12:00 AM') {
753
+ post.time = '00:00';
754
+ } else if (post.time.toUpperCase() === '12:30 AM') {
755
+ post.time = '00:30';
756
  }
757
 
758
  var time;
759
+ if (post.time !== '') {
760
  time = Date.parse(post.time);
761
  } else {
762
  time = Date.parse('10:00:00'); // If we don't have a time set, default it to 10am
763
  }
764
+
765
  var formattedtime = time.format('H:i:s');
766
+
767
+ var formattedDate = encodeURIComponent(edcal.getDayFromDayId(post.date).toString(edcal.wp_dateFormat) + ' ' + formattedtime);
768
+ var url = edcal.ajax_url() + '&action=edcal_savepost';
769
+ var postData = 'date=' + formattedDate +
770
+ '&title=' + encodeURIComponent(post.title) +
771
+ '&content=' + encodeURIComponent(post.content) +
772
+ '&id=' + encodeURIComponent(post.id) +
773
+ '&status=' + encodeURIComponent(post.status);
774
+
775
+ if (edcal.getUrlVars().post_type) {
776
+ postData += '&post_type=' + encodeURIComponent(edcal.getUrlVars().post_type);
777
+ }
778
+
779
  if (doPublish) {
780
+ postData += '&dopublish=' + encodeURIComponent('future');
781
  }
782
 
783
+ jQuery.ajax({
784
  url: url,
785
+ type: 'POST',
786
  processData: false,
787
  data: postData,
788
  timeout: 100000,
789
+ dataType: 'json',
790
  success: function(res) {
791
+ jQuery('#edit-slug-buttons').removeClass('tiploading');
792
  jQuery('#tooltip').hide();
793
  if (res.error) {
794
  /*
800
  }
801
  return;
802
  }
803
+
804
  if (!res.post) {
805
+ edcal.showError('There was an error creating a new post for your blog.');
806
  } else {
807
  if (doEdit) {
808
  /*
809
  * If the user wanted to edit the post then we redirect
810
  * them to the edit page.
811
  */
812
+ window.location = res.post.editlink.replace('&amp;', '&');
813
  } else {
814
+
815
  if (res.post.id) {
816
+ edcal.removePostItem(res.post.date, 'post-' + res.post.id);
817
  }
818
+
819
  edcal.addPostItem(res.post, res.post.date);
820
  edcal.addPostItemDragAndToolltip(res.post.date);
821
  }
826
  }
827
  },
828
  error: function(xhr) {
829
+ jQuery('#edit-slug-buttons').removeClass('tiploading');
830
  jQuery('#tooltip').hide();
831
  edcal.showError(edcal.general_error);
832
  if (xhr.responseText) {
833
+ edcal.output('savePost xhr.responseText: ' + xhr.responseText);
834
  }
835
  }
836
  });
837
  return false;
838
  },
839
+
840
  /*
841
  * Collects form values for the post inputted by the user into an object
842
  */
843
  serializePost: function() {
844
  var post = {};
845
+
846
  jQuery('#tooltip').find('input, textarea, select').each(function() {
847
  post[this.name] = this.value;
848
  });
849
  return post;
850
  },
851
+
852
  /*
853
  * Accepts new or existing post data and then populates text fields as necessary
854
  */
855
  showForm: function(post) {
856
  edcal.resetForm();
857
+
858
  // show tooltip
859
  jQuery('#tooltip').center().show();
860
+
861
+ if (!post.id) {
862
  jQuery('#tooltiptitle').text(edcal.str_newpost_title + post.formatteddate);
863
  } else {
864
+ jQuery('#tooltiptitle').text(sprintf(edcal.str_edit_post_title, post.typeTitle, edcal.getDayFromDayId(post.date).toString(edcal.previewDateFormat)));
865
 
866
  // sets the read-only author field
867
  //jQuery('#edcal-author-p').html(post.author);
870
  jQuery('#edcal-title-new-field').val(post.title);
871
  jQuery('#content').val(post.content);
872
  }
873
+
874
+ if (post.status === 'future') {
875
  jQuery('#newPostScheduleButton').text(edcal.str_update);
876
  }
877
+
878
  if (post.status) {
879
  jQuery('#edcal-status').val(post.status);
880
  edcal.updatePublishButton();
882
  jQuery('#edcal-status').val('draft');
883
  jQuery('#newPostScheduleButton').text(edcal.str_save);
884
  }
885
+
886
  /*
887
  If you have a status that isn't draft or future we
888
  just make it read only.
892
  jQuery('#edcal-status').append('<option class="temp" value="' + post.status + '">' + post.status + '</option>');
893
  jQuery('#edcal-status').val(post.status);
894
  }
895
+
896
+
897
+
898
  if (edcal.getDayFromDayId(post.date).compareTo(Date.today()) == -1) {
899
  /*
900
  * We only allow drafts in the past
901
  */
902
  jQuery('#edcal-status').attr('disabled', 'true');
903
  }
904
+
905
  var time = post.time;
906
  jQuery('#edcal-time').val(time);
907
+
908
  // set hidden fields: post.date, post.id
909
  jQuery('#edcal-date').val(post.date);
910
  jQuery('#edcal-id').val(post.id);
913
  * Put the focus in the post title field when the tooltip opens.
914
  */
915
 
916
+ jQuery('#edcal-title-new-field').focus();
917
+ jQuery('#edcal-title-new-field').select();
918
 
919
  /*
920
  tb_init('a.thickbox, area.thickbox, input.thickbox');
930
  });
931
  */
932
  },
933
+
934
  /*
935
  * Hides the add/edit form
936
  */
937
+ hideForm: function() {
938
  jQuery('#tooltip').hide();
939
  edcal.resetForm();
940
  },
941
+
942
  /*
943
  * Clears all the input values in the add/edit form
944
  */
945
+ resetForm: function() {
946
  jQuery('#tooltip').find('input, textarea, select').each(function() {
947
  this.value = '';
948
  });
949
+
950
  jQuery('#edcal-status').removeAttr('disabled');
951
+
952
  jQuery('#newPostScheduleButton').text(edcal.str_publish);
953
+
954
  jQuery('#tooltiptitle').text('');
955
  //jQuery('#edcal-author-p').html('');
956
+
957
  jQuery('#edcal-status').removeAttr('disabled');
958
+
959
  jQuery('#edcal-status .temp').remove();
960
  },
961
+
962
  /*
963
  Creates the HTML for a post item and adds the data for
964
  the post to the posts cache.
965
  */
966
  createPostItem: function(/*post*/ post, /*string*/ dayobjId) {
 
967
  if (!edcal.posts[dayobjId]) {
968
+ edcal.posts[dayobjId] = [];
969
  }
970
 
971
  edcal.posts[dayobjId][edcal.posts[dayobjId].length] = post;
972
+
973
+ return edcal.getPostItemString(post);
974
  },
975
+
976
  /*
977
  Finds the post object for the specified post ID in the
978
  specified day.
981
  if (edcal.posts[dayobjId]) {
982
  for (var i = 0; i < edcal.posts[dayobjId].length; i++) {
983
  if (edcal.posts[dayobjId][i] &&
984
+ 'post-' + edcal.posts[dayobjId][i].id === postId) {
985
  return edcal.posts[dayobjId][i];
986
  }
987
  }
988
  }
989
  },
990
+
991
  /*
992
  * Removes a post from the HTML and the posts cache.
993
  */
995
  if (edcal.findPostForId(dayobjId, postId)) {
996
  for (var i = 0; i < edcal.posts[dayobjId].length; i++) {
997
  if (edcal.posts[dayobjId][i] &&
998
+ 'post-' + edcal.posts[dayobjId][i].id === postId) {
999
  edcal.posts[dayobjId][i] = null;
1000
+ jQuery('#' + postId).remove();
1001
  }
1002
  }
1003
  }
1004
  },
1005
+
1006
  /*
1007
  Gets all the post items for the specified day from
1008
  the post cache.
1009
  */
1010
  getPostItems: function(/*string*/ dayobjId) {
1011
+ var postsString = '';
1012
+
1013
  if (edcal.posts[dayobjId]) {
1014
  for (var i = 0; i < edcal.posts[dayobjId].length; i++) {
1015
  if (edcal.posts[dayobjId][i]) {
1020
 
1021
  return postsString;
1022
  },
1023
+
1024
  /*
1025
  This function shows the action links for the post with the
1026
  specified ID.
1027
  */
1028
  showActionLinks: function(/*string*/ postid) {
1029
  var post = edcal.findPostForId(jQuery('#' + postid).parent().parent().parent().attr('id'), postid);
1030
+
1031
  if (edcal.inDrag || !edcal.isPostEditable(post)) {
1032
  return;
1033
  }
1034
+
1035
  var elem = jQuery('#' + postid + ' > div.postactions');
1036
+
1037
  elem.show();
1038
+
1039
+
1040
  if (elem.parent().position().top + elem.parent().height() > elem.parent().parent().height()) {
1041
  /*
1042
  This means the action links probably won't be visible and we need to
1045
  var p = jQuery('#' + postid + ' > div.postactions').parent().parent();
1046
  p.scrollTop(p.scrollTop() + 45);
1047
  }
1048
+ },
1049
+
1050
  /*
1051
  Hides the action links for the post with the specified
1052
  post ID.
1061
  This is based on the post date
1062
  */
1063
  isPostMovable: function(/*post*/ post) {
1064
+ return post.editlink && post.status !== 'publish';
1065
  },
1066
+
1067
  /*
1068
  Returns true if the post is editable and false otherwise.
1069
  This is based on user permissions
1071
  isPostEditable: function(/*post*/ post) {
1072
  return post.editlink;
1073
  },
1074
+
1075
  /*
1076
  Returns readonly if the post isn't editable
1077
  */
1078
  getPostEditableClass: function(/*post*/ post) {
1079
  if (post.editlink) {
1080
+ return '';
1081
  } else {
1082
+ return 'readonly';
1083
  }
1084
  },
1085
+
1086
  /*
1087
  * Gets the HTML string for a post.
1088
  */
1089
  getPostItemString: function(/*post*/ post) {
1090
  var posttitle = post.title;
1091
 
1092
+ if (posttitle === '') {
1093
+ posttitle = '[No Title]';
1094
  }
1095
 
1096
  if (edcal.statusPref) {
1097
+ if (post.status === 'draft' &&
1098
  post.sticky === '1') {
1099
  /*
1100
  * Then this post is a sticky draft
1101
  */
1102
  posttitle += edcal.str_draft_sticky;
1103
+ } else if (post.status === 'pending' &&
1104
  post.sticky === '1') {
1105
  /*
1106
  * Then this post is a sticky pending post
1108
  posttitle += edcal.str_pending_sticky;
1109
  } else if (post.sticky === '1') {
1110
  posttitle += edcal.str_sticky;
1111
+ } else if (post.status === 'pending') {
1112
  posttitle += edcal.str_pending;
1113
+ } else if (post.status === 'draft') {
1114
  posttitle += edcal.str_draft;
1115
+ } else if (post.status !== 'publish' &&
1116
+ post.status !== 'future' &&
1117
+ post.status !== 'pending') {
1118
  /*
1119
  There are some WordPress plugins that let you specify
1120
  custom post status. In that case we just want to show
1127
  if (edcal.timePref) {
1128
  posttitle = '<span class="posttime">' + post.formattedtime + '</span> ' + posttitle;
1129
  }
1130
+
1131
  if (edcal.authorPref) {
1132
+ posttitle = sprintf(edcal.str_by, posttitle, '<span class="postauthor">' + post.author + '</span>');
1133
  }
1134
+
1135
  var classString = '';
1136
+
1137
  if (edcal.isPostMovable(post)) {
1138
+ return '<li onmouseover="edcal.showActionLinks(\'post-' + post.id + '\');" ' +
1139
+ 'onmouseout="edcal.hideActionLinks(\'post-' + post.id + '\');" ' +
1140
+ 'id="post-' + post.id + '" class="post ' + post.status + ' ' + edcal.getPostEditableClass(post) + '"><div class="postlink ' + classString + '">' + posttitle + '</div>' +
1141
+ '<div class="postactions">' +
1142
  '<a href="' + post.editlink + '">' + edcal.str_edit + '</a> | ' +
1143
+ '<a href="#" onclick="edcal.editPost(' + post.id + '); return false;">' + edcal.str_quick_edit + '</a> | ' +
1144
  '<a href="' + post.dellink + '" onclick="return edcal.confirmDelete(\'' + post.title + '\');">' + edcal.str_del + '</a> | ' +
1145
+ '<a href="' + post.permalink + '">' + edcal.str_view + '</a>' +
1146
  '</div></li>';
1147
  } else {
1148
+ return '<li onmouseover="edcal.showActionLinks(\'post-' + post.id + '\');" ' +
1149
+ 'onmouseout="edcal.hideActionLinks(\'post-' + post.id + '\');" ' +
1150
+ 'id="post-' + post.id + '" class="post ' + post.status + ' ' + edcal.getPostEditableClass(post) + '"><div class="postlink ' + classString + '">' + posttitle + '</div>' +
1151
+ '<div class="postactions">' +
1152
  '<a href="' + post.editlink + '">' + edcal.str_republish + '</a> | ' +
1153
+ '<a href="' + post.permalink + '">' + edcal.str_view + '</a>' +
1154
  '</div></li>';
1155
  }
1156
  },
1157
+
1158
  /*
1159
  Finds the calendar cell for the current day and adds the
1160
  class "today" to that cell.
1164
  We want to set a class for the cell that represents the current day so we can
1165
  give it a background color.
1166
  */
1167
+ jQuery('#' + Date.today().toString(edcal.internalDateFormat)).addClass('today');
1168
  },
1169
+
1170
  /*
1171
  Most browsers need us to set a calendar height in pixels instead
1172
  of percent. This function get the correct pixel height for the
1174
  */
1175
  getCalHeight: function() {
1176
  var myHeight = jQuery(window).height() - jQuery('#footer').height() - jQuery('#wphead').height() - 150;
1177
+
1178
  /*
1179
  We don't want to make the calendar too short even if the
1180
  user's screen is super short.
1181
  */
1182
  return Math.max(myHeight, 500);
1183
  },
1184
+
1185
  /*
1186
  Moves the calendar a certain number of steps in the specified direction.
1187
  True moves the calendar down into the future and false moves the calendar
1188
  up into the past.
1189
  */
1190
  move: function(/*int*/ steps, /*boolean*/ direction, /*function*/ callback) {
1191
+ /*
1192
  * If the add/edit post form is visible, don't go anywhere.
1193
  */
1194
+ if (jQuery('#tooltip').is(':visible')) {
1195
  return;
1196
  }
1197
+
1198
  /*
1199
  The working date is a marker for the last calendar row we created.
1200
  If we are moving forward that will be the last row, if we are moving
1211
  edcal.steps = 0;
1212
  edcal.moveDate = edcal._wDate;
1213
  }
1214
+
1215
  edcal.currentDirection = direction;
1216
+
1217
  var i;
1218
+
1219
+
1220
  if (direction) {
1221
  for (i = 0; i < steps; i++) {
1222
+ jQuery('#cal > div:first').remove();
1223
+ edcal.createRow(jQuery('#cal'), true);
1224
  edcal._wDate.add(7).days();
1225
  }
1226
  edcal.alignCal();
1227
  } else {
1228
  for (i = 0; i < steps; i++) {
1229
+ jQuery('#cal > div:last').remove();
1230
+ edcal.createRow(jQuery('#cal'), false);
1231
  edcal._wDate.add(-7).days();
1232
  }
1233
  edcal.alignCal();
1234
  }
1235
+
1236
  edcal.setClassforToday();
1237
  edcal.setDateLabel();
1238
 
1239
  /*
1240
+ * If the user clicks quickly or uses the mouse wheel they can
1241
+ * get a lot of move events very quickly and we need to batch
1242
  * them up together. We set a timeout and clear it if there is
1243
  * another move before the timeout happens.
1244
  */
1250
  }
1251
 
1252
  edcal.tID = setTimeout(function() {
1253
+
1254
  /*
1255
+ * Now that we are done moving the calendar we need to get the posts for the
1256
  * new dates. We want to load the posts between the place the calendar was
1257
  * at when the user started moving it and the place the calendar is at now.
1258
  */
1259
  if (!direction) {
1260
+ edcal.getPosts(edcal._wDate.clone(),
1261
  edcal._wDate.clone().add(7 * (edcal.steps + 1)).days(),
1262
  callback);
1263
  } else {
1264
+ edcal.getPosts(edcal._wDate.clone().add(-7 * (edcal.steps + 1)).days(),
1265
  edcal._wDate.clone(),
1266
  callback);
1267
  }
1270
  edcal.tID = null;
1271
  edcal.moveDate = edcal._wDate;
1272
  }, 1000);
1273
+
1274
  if (direction) {
1275
  /*
1276
  If we are going into the future then wDate is way in the
1294
  issue by adding the spaces back before we parse.
1295
  */
1296
  getDayFromDayId: function(/*dayId*/ day) {
1297
+ return Date.parseExact(day.substring(2, 4) + '/' + day.substring(0, 2) + '/' + day.substring(4), 'MM/dd/yyyy');
1298
  },
1299
+
1300
  /*
1301
  This is a helper method to set the date label on the top of
1302
  the calendar. It looks like November 2009-December2009
1303
  */
1304
  setDateLabel: function(year) {
1305
+ var api = jQuery('#edcal_scrollable').scrollable();
1306
  var items = api.getVisibleItems();
1307
+
1308
  /*
1309
  We need to get the first day in the first week and the
1310
  last day in the last week. We call children twice to
1311
  work around a small JQuery issue.
1312
  */
1313
+ var firstDate = edcal.getDayFromDayId(items.eq(0).children('.row').children('.day:first').attr('id'));
1314
+ var lastDate = edcal.getDayFromDayId(items.eq(edcal.weeksPref - 1).children('.row').children('.day:last').attr('id'));
1315
+
1316
+ jQuery('#currentRange').text(firstDate.toString('MMMM yyyy') + ' - ' + lastDate.toString('MMMM yyyy'));
1317
  },
1318
 
1319
  /*
1320
  * We want the calendar to start on the day of the week that matches the country
1321
  * code in the locale. If their full locale is en-US, that means the country
1322
+ * code is US.
1323
  *
1324
  * This is the full list of start of the week days from unicode.org
1325
  * http://unicode.org/repos/cldr/trunk/common/supplemental/supplementalData.xml
1329
  if (edcal.startOfWeek === null) {
1330
  if (edcal.locale) {
1331
  var local = edcal.locale.toUpperCase();
1332
+
1333
+ if (edcal.endsWith(local, 'AS') ||
1334
+ edcal.endsWith(local, 'AZ') ||
1335
+ edcal.endsWith(local, 'BW') ||
1336
+ edcal.endsWith(local, 'CA') ||
1337
+ edcal.endsWith(local, 'CN') ||
1338
+ edcal.endsWith(local, 'FO') ||
1339
+ edcal.endsWith(local, 'GB') ||
1340
+ edcal.endsWith(local, 'GE') ||
1341
+ edcal.endsWith(local, 'GL') ||
1342
+ edcal.endsWith(local, 'GU') ||
1343
+ edcal.endsWith(local, 'HK') ||
1344
+ edcal.endsWith(local, 'IE') ||
1345
+ edcal.endsWith(local, 'IL') ||
1346
+ edcal.endsWith(local, 'IN') ||
1347
+ edcal.endsWith(local, 'IS') ||
1348
+ edcal.endsWith(local, 'JM') ||
1349
+ edcal.endsWith(local, 'JP') ||
1350
+ edcal.endsWith(local, 'KG') ||
1351
+ edcal.endsWith(local, 'KR') ||
1352
+ edcal.endsWith(local, 'LA') ||
1353
+ edcal.endsWith(local, 'MH') ||
1354
+ edcal.endsWith(local, 'MN') ||
1355
+ edcal.endsWith(local, 'MO') ||
1356
+ edcal.endsWith(local, 'MP') ||
1357
+ edcal.endsWith(local, 'MT') ||
1358
+ edcal.endsWith(local, 'NZ') ||
1359
+ edcal.endsWith(local, 'PH') ||
1360
+ edcal.endsWith(local, 'PK') ||
1361
+ edcal.endsWith(local, 'SG') ||
1362
+ edcal.endsWith(local, 'SY') ||
1363
+ edcal.endsWith(local, 'TH') ||
1364
+ edcal.endsWith(local, 'TT') ||
1365
+ edcal.endsWith(local, 'TW') ||
1366
+ edcal.endsWith(local, 'UM') ||
1367
+ edcal.endsWith(local, 'US') ||
1368
+ edcal.endsWith(local, 'UZ') ||
1369
+ edcal.endsWith(local, 'VI') ||
1370
+ edcal.endsWith(local, 'ZW')) {
1371
 
1372
  /*
1373
  * Sunday
1374
  */
1375
  edcal.startOfWeek = 0;
1376
+ } else if (edcal.endsWith(local, 'MV')) {
1377
  /*
1378
  * Friday
1379
  */
1380
  edcal.startOfWeek = 5;
1381
+ } else if (edcal.endsWith(local, 'AF') ||
1382
+ edcal.endsWith(local, 'BH') ||
1383
+ edcal.endsWith(local, 'DJ') ||
1384
+ edcal.endsWith(local, 'DZ') ||
1385
+ edcal.endsWith(local, 'EG') ||
1386
+ edcal.endsWith(local, 'ER') ||
1387
+ edcal.endsWith(local, 'ET') ||
1388
+ edcal.endsWith(local, 'IQ') ||
1389
+ edcal.endsWith(local, 'IR') ||
1390
+ edcal.endsWith(local, 'JO') ||
1391
+ edcal.endsWith(local, 'KE') ||
1392
+ edcal.endsWith(local, 'KW') ||
1393
+ edcal.endsWith(local, 'LY') ||
1394
+ edcal.endsWith(local, 'MA') ||
1395
+ edcal.endsWith(local, 'OM') ||
1396
+ edcal.endsWith(local, 'QA') ||
1397
+ edcal.endsWith(local, 'SA') ||
1398
+ edcal.endsWith(local, 'SD') ||
1399
+ edcal.endsWith(local, 'SO') ||
1400
+ edcal.endsWith(local, 'TN') ||
1401
+ edcal.endsWith(local, 'YE')) {
1402
  /*
1403
  * Sunday
1404
  */
1423
 
1424
  /*
1425
  * Just a little helper function to tell if a given string (str)
1426
+ * ends with the given expression (expr). I could adding this
1427
  * function to the JavaScript string object, but I don't want to
1428
  * risk conflicts with other plugins.
1429
  */
1430
  endsWith: function(/*string*/ str, /*string*/ expr) {
1431
+ return (str.match(expr + '$') == expr);
1432
  },
1433
+
1434
  /*
1435
  * Moves the calendar to the specified date.
1436
  */
1437
  moveTo: function(/*Date*/ date) {
1438
  edcal.isMoving = true;
1439
+ jQuery('#cal').empty();
1440
+
1441
  jQuery.cookie('edcal_date', date.toString('yyyy-dd-MM'));
1442
 
1443
  /*
1445
  the next Sunday.
1446
  */
1447
  edcal._wDate = edcal.nextStartOfWeek(date).add(-21).days();
1448
+
1449
  /*
1450
  After we remove and redo all the rows we are back to
1451
  moving in a going down direction.
1452
  */
1453
+
1454
  edcal.currentDirection = true;
1455
+
1456
  var count = edcal.weeksPref + 6;
1457
+
1458
  for (var i = 0; i < count; i++) {
1459
+ edcal.createRow(jQuery('#cal'), true);
1460
  edcal._wDate.add(7).days();
1461
  }
1462
 
1463
  edcal.alignCal();
1464
+
1465
+ var api = jQuery('#edcal_scrollable').scrollable();
1466
+
1467
  api.move(2);
1468
 
1469
  edcal.setDateLabel();
1477
  save it.
1478
  */
1479
  savePosition: function() {
1480
+ var cal = jQuery('#edcal_scrollable');
1481
  edcal.position = {
1482
  top: cal.offset().top,
1483
  bottom: cal.offset().top + cal.height()
1490
  on the width of a day in the calendar and not anything in a style.
1491
  That works well for the posts in the calendar, but it means we need
1492
  to dynamically determine the width of the post when dragging.
1493
+
1494
  This value will remain the same until the calendar resizes. That is
1495
  why we do it here. We need to get the width of the first visible day
1496
  in the calendar which is why we use the complicated selector. We also
1497
  need to generate a style for it since the drag element doesn't exist
1498
  yet and using the live function would really slow down the drag operation.
1499
+
1500
  We base this on the width of a way since they might not have any posts
1501
  yet.
1502
  */
1503
  jQuery('#edcal_poststyle').remove();
1504
+
1505
  /*
1506
  We need to figure out the height of each post list. They all have the same
1507
  height so we just look at the first visible list and set some styles on the
1508
  page to set the post list height based on that. We reset the value every
1509
  time the page refreshes.
1510
  */
1511
+ var dayHeight = jQuery('.rowcont:eq(2) .dayobj:first').height() - jQuery('.rowcont:eq(2) .daylabel:first').height() - 6;
1512
+
1513
+ jQuery('head').append('<style id="edcal_poststyle" type="text/css">.ui-draggable-dragging {' +
1514
+ 'width: ' + (jQuery('.rowcont:eq(2) .day:first').width() - 5) + 'px;' +
1515
+ '}' +
1516
+ '.postlist {' +
1517
+ 'height: ' + dayHeight + 'px;' +
1518
+ '}' +
1519
  '</style>');
1520
  },
1521
 
1542
  * Sends no feedback and hides the section
1543
  */
1544
  noFeedback: function() {
1545
+ jQuery('#feedbacksection').hide('fast');
1546
  edcal.saveFeedbackPref();
1547
  },
1548
 
1550
  * Saves the feedback preference to the server
1551
  */
1552
  saveFeedbackPref: function() {
1553
+ var url = edcal.ajax_url() + '&action=edcal_saveoptions&dofeedback=' + encodeURIComponent('done');
1554
+
1555
+ jQuery.ajax({
1556
  url: url,
1557
+ type: 'POST',
1558
  processData: false,
1559
  timeout: 100000,
1560
+ dataType: 'text',
1561
  success: function(res) {
1562
  jQuery('#feedbacksection').html(edcal.str_feedbackdone);
1563
  setTimeout(function() {
1564
+ jQuery('#feedbacksection').hide('slow');
1565
  }, 5000);
1566
  },
1567
  error: function(xhr) {
1568
  edcal.showError(edcal.general_error);
1569
  if (xhr.responseText) {
1570
+ edcal.output('saveOptions xhr.responseText: ' + xhr.responseText);
1571
  }
1572
  }
1573
  });
1574
 
1575
  },
1576
+
1577
  /*
1578
  * Initializes the calendar
1579
  */
1580
  init: function() {
1581
+ if (jQuery('#edcal_scrollable').length === 0) {
1582
  /*
1583
+ * This means we are on a page without the editorial
1584
  * calendar
1585
  */
1586
  return;
1588
 
1589
  edcal.addFeedbackSection();
1590
 
1591
+ jQuery('#loading').hide();
1592
+
1593
+ jQuery('#edcal_scrollable').css('height', edcal.getCalHeight() + 'px');
1594
  edcal.windowHeight = jQuery(window).height();
1595
+
1596
  /*
1597
  * Add the days of the week
1598
+ */
1599
  edcal.createDaysHeader();
1600
+
1601
  /*
1602
  * We start by initializting the scrollable. We use this to manage the
1603
  * scrolling of the calendar, but don't actually call it to animate the
1606
  *
1607
  * This doesn't really change anything since the animation happens offscreen.
1608
  */
1609
+ jQuery('#edcal_scrollable').scrollable({
1610
+ vertical: true,
1611
  size: edcal.weeksPref,
1612
  keyboardSteps: 1,
1613
  speed: 100,
1614
+ easing: 'linear'
1615
+ // use mousewheel plugin
1616
  }).mousewheel();
1617
+
1618
+ var api = jQuery('#edcal_scrollable').scrollable();
1619
+
1620
  /*
1621
  When the user moves the calendar around we remember their
1622
  date and save it in a cookie. Then we read the cookie back
1624
  it last.
1625
  */
1626
  var curDate = jQuery.cookie('edcal_date');
1627
+
1628
  if (curDate) {
1629
  curDate = Date.parseExact(curDate, 'yyyy-dd-MM');
1630
  edcal.output('Resetting to date from the edcal_Date cookie: ' + curDate);
1631
  } else {
1632
  curDate = Date.today();
1633
  }
1634
+
1635
  edcal.moveTo(curDate.clone());
1636
 
1637
  /*
1638
+ * The scrollable handles some basic binding. This gets us
1639
+ * up arrow, down arrow and the mouse wheel.
1640
  */
1641
+ api.onBeforeSeek(function(evt, direction) {
1642
+ // inside callbacks the "this" variable is a reference to the API
1643
  /*
1644
  * Some times for reasons I haven't been able to figure out
1645
  * the direction is an int instead of a boolean. I don't
1650
  } else if (direction === 3) {
1651
  direction = true;
1652
  }
1653
+
1654
  if (!edcal.isMoving) {
1655
  edcal.move(1, direction);
1656
  }
1657
+
1658
  return false;
1659
  });
1660
 
1661
  /*
1662
  * We also want to listen for a few other key events
1663
  */
1664
+ jQuery(document).bind('keydown', function(evt) {
1665
  //if (evt.altKey || evt.ctrlKey) { return; }
1666
  //output("evt.altKey: " + evt.altKey);
1667
  //output("evt.keyCode: " + evt.keyCode);
1668
  //output("evt.ctrlKey: " + evt.ctrlKey);
1669
+
1670
  if ((evt.keyCode === 34 && !(evt.altKey || evt.ctrlKey)) || //page down
1671
+ evt.keyCode === 40 && evt.ctrlKey) { // Ctrl+down down arrow
1672
  edcal.move(edcal.weeksPref, true);
1673
  return false;
1674
  } else if ((evt.keyCode === 33 && !(evt.altKey || evt.ctrlKey)) || //page up
1675
+ evt.keyCode === 38 && evt.ctrlKey) { // Ctrl+up up arrow
1676
  edcal.move(edcal.weeksPref, false);
1677
  return false;
1678
  } else if (evt.keyCode === 27) { //escape key
1680
  return false;
1681
  }
1682
  });
1683
+
1684
+ edcal.getPosts(edcal.nextStartOfWeek(curDate).add(-3).weeks(),
1685
  edcal.nextStartOfWeek(curDate).add(edcal.weeksPref + 3).weeks());
1686
+
1687
  /*
1688
  Now we bind the listeners for all of our links and the window
1689
  resize.
1690
  */
1691
+ jQuery('#moveToToday').click(function() {
1692
  edcal.moveTo(Date.today());
1693
+ edcal.getPosts(edcal.nextStartOfWeek(Date.today()).add(-3).weeks(),
1694
  edcal.nextStartOfWeek(Date.today()).add(edcal.weeksPref + 3).weeks());
1695
  return false;
1696
  });
1697
+
1698
+ jQuery('#prevmonth').click(function() {
1699
  edcal.move(edcal.weeksPref, false);
1700
  return false;
1701
  });
1702
+
1703
+ jQuery('#nextmonth').click(function() {
1704
  edcal.move(edcal.weeksPref, true);
1705
  return false;
1706
  });
1707
+
1708
  function resizeWindow(e) {
1709
  if (edcal.windowHeight != jQuery(window).height()) {
1710
+ jQuery('#edcal_scrollable').css('height', edcal.getCalHeight() + 'px');
1711
  edcal.windowHeight = jQuery(window).height();
1712
  edcal.savePosition();
1713
  }
1714
  }
1715
+ jQuery(window).bind('resize', resizeWindow);
1716
 
1717
+ jQuery('#newPostScheduleButton').live('click', function(evt) {
1718
  // if the button is disabled, don't do anything
1719
+ if (jQuery(this).hasClass('disabled')) {
1720
  return false;
1721
  }
1722
+ // Otherwise,
1723
+ // make sure we can't make duplicate posts by clicking twice quickly
1724
+ jQuery(this).addClass('disabled');
1725
+ // and save the post
1726
  return edcal.savePost(null, false, true);
1727
  });
1728
 
1729
+ jQuery('#edcal-title-new-field').bind('keyup', function(evt) {
1730
+ if (jQuery('#edcal-title-new-field').val().length > 0 && jQuery('#edcal-time').val().length > 0) {
1731
+ jQuery('#newPostScheduleButton').removeClass('disabled');
1732
  } else {
1733
+ jQuery('#newPostScheduleButton').addClass('disabled');
1734
  }
1735
 
1736
  if (evt.keyCode == 13) { // enter key
1740
  return edcal.savePost(null, true);
1741
  }
1742
  });
1743
+
1744
+ jQuery('#edcal-status').bind('change', function(evt) {
1745
  edcal.updatePublishButton();
1746
  });
1747
 
1748
+ jQuery('#edcal_weeks_pref').live('keyup', function(evt) {
1749
+ if (jQuery('#edcal_weeks_pref').val().length > 0) {
1750
+ jQuery('#edcal_applyoptions').removeClass('disabled');
1751
  } else {
1752
+ jQuery('#edcal_applyoptions').addClass('disabled');
1753
  }
1754
+
1755
  if (evt.keyCode == 13) { // enter key
1756
  edcal.saveOptions();
1757
  }
1759
  });
1760
 
1761
  edcal.savePosition();
1762
+
1763
  edcal.addOptionsSection();
1764
+
1765
  jQuery('#edcal-time').timePicker({
1766
  show24Hours: edcal.timeFormat === 'H:i',
1767
+ separator: ':',
1768
  step: 30
1769
  });
1770
  },
1771
+
1772
  /*
1773
  This function updates the text of te publish button in the quick
1774
  edit dialog to match the current operation.
1791
  edcal.output('Changing the date of "' + post.title + '" to ' + newdate);
1792
  var newdateFormatted = edcal.getDayFromDayId(newdate).toString(edcal.wp_dateFormat);
1793
 
1794
+ var url = edcal.ajax_url() + '&action=edcal_changedate&postid=' + post.id +
1795
+ '&postStatus=' + post.status +
1796
+ '&newdate=' + newdateFormatted + '&olddate=' + edcal.getDayFromDayId(post.date).toString(edcal.wp_dateFormat);
1797
+
1798
+ jQuery('#post-' + post.id).addClass('loadingclass');
1799
 
1800
+ jQuery.ajax({
 
 
1801
  url: url,
1802
+ type: 'POST',
1803
  processData: false,
1804
  timeout: 100000,
1805
+ dataType: 'json',
1806
  success: function(res) {
1807
  if (res.error) {
1808
  /*
1809
  * If there was an error we need to remove the dropped
1810
  * post item.
1811
  */
1812
+ edcal.removePostItem(newdate, 'post-' + res.post.id);
1813
  if (res.error === edcal.CONCURRENCY_ERROR) {
1814
  edcal.displayMessage(edcal.concurrency_error + '<br />' + res.post.title);
1815
  } else if (res.error === edcal.PERMISSION_ERROR) {
1817
  } else if (res.error === edcal.NONCE_ERROR) {
1818
  edcal.displayMessage(edcal.checksum_error);
1819
  }
1820
+ }
1821
 
1822
+ edcal.removePostItem(res.post.date, 'post-' + res.post.id);
1823
  edcal.addPostItem(res.post, res.post.date);
1824
  edcal.addPostItemDragAndToolltip(res.post.date);
1825
 
1829
  },
1830
  error: function(xhr, textStatus, error) {
1831
  edcal.showError(edcal.general_error);
1832
+
1833
+ edcal.output('textStatus: ' + textStatus);
1834
+ edcal.output('error: ' + error);
1835
  if (xhr.responseText) {
1836
+ edcal.output('changeDate xhr.responseText: ' + xhr.responseText);
1837
  }
1838
  }
1839
  });
1840
 
1841
  },
1842
+
1843
  /*
1844
  Makes an AJAX call to get the posts from the server within the
1845
  specified dates.
1846
  */
1847
  getPosts: function(/*Date*/ from, /*Date*/ to, /*function*/ callback) {
1848
+ edcal.output('Getting posts from ' + from + ' to ' + to);
1849
+
1850
  var shouldGet = edcal.cacheDates[from];
1851
 
1852
  if (shouldGet) {
1855
  * that we have already covered. This is cutting down on
1856
  * it somewhat, but we could get much better about this.
1857
  */
1858
+ edcal.output('Using cached results for posts from ' + from.toString('dd-MMM-yyyy') + ' to ' + to.toString('dd-MMM-yyyy'));
1859
+
1860
  if (callback) {
1861
  callback();
1862
  }
1865
 
1866
  edcal.cacheDates[from] = true;
1867
 
1868
+ var url = edcal.ajax_url() + '&action=edcal_posts&from=' + from.toString('yyyy-MM-dd') + '&to=' + to.toString('yyyy-MM-dd');
1869
+
1870
+ if (edcal.getUrlVars().post_type) {
1871
+ url += '&post_type=' + encodeURIComponent(edcal.getUrlVars().post_type);
1872
+ }
1873
 
1874
+ jQuery('#loading').show();
1875
+
1876
+ jQuery.ajax({
1877
  url: url,
1878
+ type: 'GET',
1879
  processData: false,
1880
  timeout: 100000,
1881
+ dataType: 'text',
1882
  success: function(res) {
1883
+ jQuery('#loading').hide();
1884
  /*
1885
  * These result here can get pretty large on a busy blog and
1886
  * the JSON parser from JSON.org works faster than the native
1887
  * one used by JQuery.
1888
  */
1889
  var parsedRes = JSON.parseIt(res);
1890
+
1891
  if (parsedRes.error) {
1892
  /*
1893
  * If there was an error we need to remove the dropped
1899
  return;
1900
  }
1901
  var postDates = [];
1902
+
1903
  /*
1904
  We get the posts back with the most recent post first. That
1905
  is what most blogs want. However, we want them in the other
1919
  * case to make sure we don't get into trouble.
1920
  */
1921
  post.date = post.date.replace(post.date.substring(2, 3), post.date.substring(2, 3).toUpperCase());
1922
+
1923
+ edcal.removePostItem(post.date, 'post-' + post.id);
1924
  edcal.addPostItem(post, post.date);
1925
  postDates[postDates.length] = post.date;
1926
  }
1928
 
1929
  /*
1930
  * If the blog has a very larger number of posts then adding
1931
+ * them all can make the UI a little slow. Particularly IE
1932
+ * pops up a warning giving the user a chance to abort the
1933
  * script. Adding tooltips and making the items draggable is
1934
  * a lot of what makes things slow. Delaying those two operations
1935
  * makes the UI show up much faster and the user has to wait
1937
  * stop complaining.
1938
  */
1939
  setTimeout(function() {
1940
+ edcal.output('Finished adding draggable support to ' + postDates.length + ' posts.');
1941
  jQuery.each(postDates, function(i, postDate) {
1942
  edcal.addPostItemDragAndToolltip(postDate);
1943
  });
1944
  }, 300);
1945
+
1946
  if (callback) {
1947
  callback(res);
1948
  }
1949
+
1950
  },
1951
  error: function(xhr) {
1952
  edcal.showError(edcal.general_error);
1953
  if (xhr.responseText) {
1954
+ edcal.output('getPosts xhr.responseText: ' + xhr.responseText);
1955
  }
1956
  }
1957
  });
1958
  },
1959
+
1960
  /*
1961
  * Retreives a single post item based on the id
1962
  * Can optionally pass a callback function that is triggered
1963
+ * when the call successfully completes. The post object is passed
1964
  * as a parameter for the callback.
1965
  */
1966
  getPost: function(/*int*/ postid, /*function*/ callback) {
1967
+
1968
  if (postid === 0) {
1969
  return false;
1970
  }
1971
+
1972
  // show loading
1973
+ jQuery('#loading').show();
1974
+
1975
+ var url = edcal.ajax_url() + '&action=edcal_getpost&postid=' + postid;
1976
+
1977
+ if (edcal.getUrlVars().post_type) {
1978
+ url += '&post_type=' + encodeURIComponent(edcal.getUrlVars().post_type);
1979
+ }
1980
+
1981
+ jQuery.ajax({
1982
  url: url,
1983
+ type: 'GET',
1984
  processData: false,
1985
  timeout: 100000,
1986
+ dataType: 'json',
1987
  success: function(res) {
1988
  // hide loading
1989
+ jQuery('#loading').hide();
1990
+
1991
+ edcal.output('xhr for getPost returned: ' + res);
1992
  if (res.error) {
1993
  if (res.error === edcal.NONCE_ERROR) {
1994
  edcal.showError(edcal.checksum_error);
2002
  },
2003
  error: function(xhr) {
2004
  // hide loading
2005
+ jQuery('#loading').hide();
2006
+
2007
  edcal.showError(edcal.general_error);
2008
  if (xhr.responseText) {
2009
+ edcal.output('getPost xhr.responseText: ' + xhr.responseText);
2010
  }
2011
  return false;
2012
  }
2013
  });
2014
  },
2015
+
2016
  /*
2017
  This function adds the scren options tab to the top of the screen. I wish
2018
  WordPress had a hook so I could provide this in PHP, but as of version 2.9.1
2020
  doing this in JavaScript.
2021
  */
2022
  addOptionsSection: function() {
2023
+ var html =
2024
+ '<div class="hide-if-no-js screen-meta-toggle" id="screen-options-link-wrap">' +
2025
+ '<a class="show-settings" ' +
2026
+ 'id="show-edcal-settings-link" ' +
2027
+ 'onclick="edcal.toggleOptions(); return false;" ' +
2028
+ 'href="#" ' +
2029
+ 'style="background-image: url(images/screen-options-right.gif);">' + edcal.str_screenoptions + '</a>' +
2030
  '</div>';
2031
+
2032
+ jQuery('#screen-meta-links').append(html);
2033
  },
2034
+
2035
  /*
2036
  Respond to clicks on the Screen Options tab by sliding it down when it
2037
  is up and sliding it up when it is down.
2041
  /*
2042
  Show the screen options section. We start by saving off the old HTML
2043
  */
2044
+ edcal.helpMeta = jQuery('#contextual-help-wrap').html();
2045
 
2046
  /*
2047
  * Set up the visible fields option
2048
  */
2049
  var optionsHtml = '<div class="metabox-prefs" id="calendar-fields-prefs">' +
2050
+ '<h5>' + edcal.str_show_opts + '</h5>' +
2051
+ '<label for="author-hide">' +
2052
  '<input type="checkbox" ' + edcal.isPrefChecked(edcal.authorPref) + 'value="true" id="author-hide" ' +
2053
+ 'name="author-hide" class="hide-column-tog" />' + edcal.str_opt_author +
2054
+ '</label>' +
2055
+ '<label for="status-hide">' +
2056
  '<input type="checkbox" ' + edcal.isPrefChecked(edcal.statusPref) + 'value="true" id="status-hide" ' +
2057
+ 'name="status-hide" class="hide-column-tog" />' + edcal.str_opt_status +
2058
+ '</label>' +
2059
+ '<label for="time-hide">' +
2060
+ '<input type="checkbox" ' + edcal.isPrefChecked(edcal.timePref) + 'value="true" id="time-hide" ' +
2061
+ 'name="time-hide" class="hide-column-tog" />' + edcal.str_opt_time +
2062
+ '</label>' +
2063
  '</div>';
2064
+
2065
  /*
2066
  * Set up the number of posts option
2067
  */
2068
+ optionsHtml += '<div class="metabox-prefs">' +
2069
+ '<h5>' + edcal.str_show_title + '</h5>' +
2070
  '<select id="edcal_weeks_pref" ' + 'class="screen-per-page" title="' + edcal.str_weekstt + '"> ';
2071
 
2072
  var weeks = parseInt(edcal.weeksPref, 10);
2078
  }
2079
  }
2080
 
2081
+ optionsHtml += '</select>' +
2082
+ edcal.str_opt_weeks +
2083
  '</div>';
2084
+
2085
  /*
2086
  I started work on adding a color picker so you could choose the color for
2087
  drafts, published posts, and scheduled posts. However, that makes the settings
2089
  */
2090
  //optionsHtml += '<h5>' + edcal.str_optionscolors + '</h5>';
2091
  //optionsHtml += edcal.generateColorPicker(edcal.str_optionsdraftcolor, 'draft-color', 'lightgreen');
2092
+
2093
+
2094
  optionsHtml += '<br /><button id="edcal_applyoptions" onclick="edcal.saveOptions(); return false;" class="save button">' + edcal.str_apply + '</button>';
2095
+
2096
+ jQuery('#contextual-help-wrap').html(optionsHtml);
2097
+
2098
+ jQuery('#contextual-help-link-wrap').css('visibility', 'hidden');
2099
+
2100
  jQuery('#contextual-help-wrap').slideDown('normal');
2101
+
2102
+ jQuery('#show-edcal-settings-link').css('background-image', 'url(images/screen-options-right-up.gif)');
2103
  } else {
2104
  jQuery('#contextual-help-wrap').slideUp('fast');
2105
+
2106
  /*
2107
  * restore the old HTML
2108
  */
2109
+ jQuery('#contextual-help-wrap').html(edcal.helpMeta);
2110
+
2111
  edcal.helpMeta = null;
2112
+
2113
+ jQuery('#show-edcal-settings-link').css('background-image', 'url(images/screen-options-right.gif)');
2114
+ jQuery('#contextual-help-link-wrap').css('visibility', '');
2115
  }
2116
  },
2117
+
2118
  generateColorPicker: function(/*String*/ title, /*string*/ id, /*string*/ value) {
2119
  var html = '<div id="' + id + '" class="optionscolorrow">';
2120
+
2121
  html += '<span style="background-color: ' + value + ';" class="colorlabel"> ' + title + '</span> ';
2122
+
2123
+ var colors = ['lightred', 'orange', 'yellow', 'lightgreen', 'lightblue', 'purple', 'lightgray'];
2124
+
2125
+ edcal.output('colors.length: ' + colors.length);
2126
  for (var i = 0; i < colors.length; i++) {
2127
  html += '<a href="#" class="optionscolor ';
2128
+
2129
  if (colors[i] === value) {
2130
  html += 'colorselected';
2131
+
2132
  }
2133
+
2134
+ html += '" class=' + id + colors[i] + '" style="background-color: ' + colors[i] + '; left: ' + ((i * 20) + 50) + 'px" ' +
2135
  'onclick="edcal.selectColor(\'' + id + '\', \'' + colors[i] + '\'); return false;"></a>';
2136
+
2137
  }
2138
+
2139
  html += '</div>';
2140
+
2141
  return html;
2142
+
2143
  },
2144
+
2145
  selectColor: function(/*string*/ id, /*string*/ value) {
2146
+ edcal.output('selectColor(' + id + ', ' + value + ')');
2147
  jQuery('#' + id + ' .colorlabel').css('background-color', value);
2148
+
2149
  jQuery('#' + id + ' .colorselected').removeClass('colorselected');
2150
+
2151
  jQuery('#' + id + 'value').addClass('colorselected');
2152
+
2153
  },
2154
+
2155
  isPrefChecked: function(/*boolean*/ prefVal) {
2156
  if (prefVal) {
2157
  return ' checked="checked" ';
2159
  return '';
2160
  }
2161
  },
2162
+
2163
  /*
2164
  Save the number of weeks options with an AJAX call. This happens
2165
  when you press the apply button.
2169
  We start by validating the number of weeks. We only allow
2170
  1, 2, 3, 4, or 5 weeks at a time.
2171
  */
2172
+ if (jQuery('#edcal_weeks_pref').val() !== '1' &&
2173
+ jQuery('#edcal_weeks_pref').val() !== '2' &&
2174
+ jQuery('#edcal_weeks_pref').val() !== '3' &&
2175
+ jQuery('#edcal_weeks_pref').val() !== '4' &&
2176
+ jQuery('#edcal_weeks_pref').val() !== '5') {
2177
  humanMsg.displayMsg(edcal.str_weekserror);
2178
  return;
2179
  }
2180
+
2181
+ var url = edcal.ajax_url() + '&action=edcal_saveoptions&weeks=' +
2182
+ encodeURIComponent(jQuery('#edcal_weeks_pref').val());
2183
+
2184
  jQuery('#calendar-fields-prefs').find('input, textarea, select').each(function() {
2185
  url += '&' + encodeURIComponent(this.name) + '=' + encodeURIComponent(this.checked);
2186
  });
2187
+
2188
+ jQuery.ajax({
2189
  url: url,
2190
+ type: 'POST',
2191
  processData: false,
2192
  timeout: 100000,
2193
+ dataType: 'text',
2194
  success: function(res) {
2195
  /*
2196
  Now we refresh the page because I'm too lazy to
2201
  error: function(xhr) {
2202
  edcal.showError(edcal.general_error);
2203
  if (xhr.responseText) {
2204
+ edcal.output('saveOptions xhr.responseText: ' + xhr.responseText);
2205
  }
2206
  }
2207
  });
2208
  },
2209
+
2210
  /**
2211
  * Outputs info messages to the Firebug console if it is available.
2212
+ *
2213
+ * msg the message to write.
2214
  */
2215
  output: function(msg) {
2216
  if (window.console) {
2217
  console.info(msg);
2218
  }
2219
  },
2220
+
2221
  /*
2222
+ * Shows an error message and sends the message as an error to the
2223
  * Firebug console if it is available.
2224
  */
2225
  showError: function(/*string*/ msg) {
2228
  }
2229
 
2230
  edcal.displayMessage(msg);
2231
+
2232
  },
2233
 
2234
  /*
2237
  displayMessage: function(/*string*/ msg) {
2238
  humanMsg.displayMsg(msg);
2239
  },
2240
+
2241
  /*
2242
  * A helper function to get the parameters from the
2243
  * current URL.
2253
 
2254
  return vars;
2255
  },
2256
+
2257
  /*
2258
  * Show an error indicating the calendar couldn't be loaded
2259
  */
2260
  showFatalError: function(message) {
2261
+ jQuery('#edcal_main_title').after(
2262
+ '<div class="updated below-h2" id="message"><p>' +
2263
+ edcal.str_fatal_error + message + '<br></p></div>');
2264
+
2265
+ if (window.console) {
2266
+ console.error(msg);
2267
+ }
2268
  }
2269
  };
2270
 
2271
  /*
2272
  * Helper function for jQuery to center a div
2273
  */
2274
+ jQuery.fn.center = function() {
2275
+ this.css('position', 'absolute');
2276
+ this.css('top', (jQuery(window).height() - this.outerHeight()) / 2 + jQuery(window).scrollTop() + 'px');
2277
+ this.css('left', (jQuery(window).width() - this.outerWidth()) / 2 + jQuery(window).scrollLeft() + 'px');
2278
  return this;
2279
  };
2280
 
2281
 
2282
+ jQuery(document).ready(function() {
2283
  try {
2284
  edcal.init();
2285
  } catch (e) {
edcal.php CHANGED
@@ -18,7 +18,7 @@
18
  /*
19
  Plugin Name: WordPress Editorial Calendar
20
  Description: The Editorial Calendar makes it possible to see all your posts and drag and drop them to manage your blog.
21
- Version: 1.2
22
  Author: Colin Vernon, Justin Evans, Mary Vogt, and Zack Grossbart
23
  Author URI: http://www.zackgrossbart.com
24
  Plugin URI: http://stresslimitdesign.com/editorial-calendar-plugin
@@ -51,6 +51,12 @@ $EDCAL_PERMISSION_ERROR = "5";
51
  */
52
  $EDCAL_NONCE_ERROR = "6";
53
 
 
 
 
 
 
 
54
  function edcal_load_language() {
55
  $plugin_dir = basename(dirname(__FILE__));
56
  load_plugin_textdomain( 'editorial-calendar', 'wp-content/plugins/' . $plugin_dir . '/languages/', $plugin_dir . '/languages/' );
@@ -60,9 +66,35 @@ function edcal_load_language() {
60
  * This function adds our calendar page to the admin UI
61
  */
62
  function edcal_list_add_management_page( ) {
 
63
  if ( function_exists('add_management_page') ) {
64
  $page = add_posts_page( __('Calendar', 'editorial-calendar'), __('Calendar', 'editorial-calendar'), 'edit_posts', 'cal', 'edcal_list_admin' );
65
  add_action( "admin_print_scripts-$page", 'edcal_scripts' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  }
67
  }
68
 
@@ -194,10 +226,8 @@ function edcal_list_admin() {
194
  * pass the values to JavaScript.
195
  */
196
 
197
- edcal.str_on = <?php echo(edcal_json_encode(__('on', 'editorial-calendar'))) ?>;
198
- edcal.str_by = <?php echo(edcal_json_encode(__('by', 'editorial-calendar'))) ?>;
199
- edcal.str_at = <?php echo(edcal_json_encode(__('at', 'editorial-calendar'))) ?>;
200
-
201
  edcal.str_addPostLink = <?php echo(edcal_json_encode(__('New Post', 'editorial-calendar'))) ?>;
202
 
203
  edcal.str_draft = <?php echo(edcal_json_encode(__(' [DRAFT]', 'editorial-calendar'))) ?>;
@@ -215,12 +245,12 @@ function edcal_list_admin() {
215
  edcal.str_posttitle = <?php echo(edcal_json_encode(__('Title', 'editorial-calendar'))) ?>;
216
  edcal.str_postcontent = <?php echo(edcal_json_encode(__('Content', 'editorial-calendar'))) ?>;
217
  edcal.str_newpost = <?php echo(edcal_json_encode(__('Add a new post on ', 'editorial-calendar'))) ?>;
218
- edcal.str_newpost_title = <?php echo(edcal_json_encode(__('New Post - ', 'editorial-calendar'))) ?>;
219
  edcal.str_update = <?php echo(edcal_json_encode(__('Update', 'editorial-calendar'))) ?>;
220
  edcal.str_publish = <?php echo(edcal_json_encode(__('Schedule', 'editorial-calendar'))) ?>;
221
  edcal.str_review = <?php echo(edcal_json_encode(__('Submit for Review', 'editorial-calendar'))) ?>;
222
  edcal.str_save = <?php echo(edcal_json_encode(__('Save', 'editorial-calendar'))) ?>;
223
- edcal.str_edit_post_title = <?php echo(edcal_json_encode(__('Edit Post - ', 'editorial-calendar'))) ?>;
224
  edcal.str_scheduled = <?php echo(edcal_json_encode(__('Scheduled', 'editorial-calendar'))) ?>;
225
 
226
  edcal.str_del_msg1 = <?php echo(edcal_json_encode(__('You are about to delete the post "', 'editorial-calendar'))) ?>;
@@ -293,7 +323,7 @@ function edcal_list_admin() {
293
 
294
  <div class="wrap">
295
  <div class="icon32" id="icon-edit"><br/></div>
296
- <h2 id="edcal_main_title"><?php echo(__('Posts Calendar', 'editorial-calendar')) ?></h2>
297
 
298
  <div id="loadingcont">
299
  <div id="loading"> </div>
@@ -474,7 +504,7 @@ function edcal_posts() {
474
  if (!edcal_checknonce()) {
475
  die();
476
  }
477
-
478
  global $edcal_startDate, $edcal_endDate;
479
  $edcal_startDate = isset($_GET['from'])?$_GET['from']:null;
480
  $edcal_endDate = isset($_GET['to'])?$_GET['to']:null;
@@ -482,10 +512,18 @@ function edcal_posts() {
482
  $args = array(
483
  'posts_per_page' => -1,
484
  'post_status' => "publish&future&draft",
485
- 'post_parent' => null, // any parent
486
- 'post_type' => 'post',
487
  );
488
 
 
 
 
 
 
 
 
 
 
489
  add_filter('posts_where', 'edcal_filter_where');
490
  $myposts = query_posts($args);
491
  remove_filter('posts_where', 'edcal_filter_where');
@@ -495,19 +533,8 @@ function edcal_posts() {
495
  $size = sizeof($myposts);
496
 
497
  for($i = 0; $i < $size; $i++) {
498
- /*
499
- * Sticky posts are ones that stick to the front page.
500
- * They do technically have a date, but it doesn't
501
- * really make sense to drag and drop them around since
502
- * the user has already indicated that they want them
503
- * to stay on the front page.
504
- */
505
-
506
  $post = $myposts[$i];
507
-
508
- //if (!is_sticky($post->ID)) {
509
- edcal_postJSON($post, $i < $size - 1);
510
- //}
511
  }
512
 
513
  ?> ]
@@ -531,9 +558,22 @@ function edcal_getpost() {
531
 
532
  // If a proper post_id wasn't passed, return
533
  if(!$post_id) die();
 
 
 
 
 
 
 
 
 
 
 
 
 
534
 
535
- $post = query_posts( array('p' => $post_id) );
536
-
537
  // get_post and setup_postdata don't get along, so we're doing a mini-loop
538
  if(have_posts()) :
539
  while(have_posts()) : the_post();
@@ -561,12 +601,44 @@ function edcal_json_encode($string) {
561
  return json_encode(str_replace("&#039;", "&#146;", $string));
562
  }
563
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
564
  /*
565
  * This function sets up the post data and prints out the values we
566
  * care about in a JSON data structure. This prints out just the
567
  * value part. If $fullPost is set to true, post_content is also returned.
568
  */
569
  function edcal_postJSON($post, $addComma = true, $fullPost = false) {
 
570
  $timeFormat = get_option("time_format");
571
  if ($timeFormat == "g:i a") {
572
  $timeFormat = "ga";
@@ -586,6 +658,20 @@ function edcal_postJSON($post, $addComma = true, $fullPost = false) {
586
  return;
587
  }
588
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
  ?>
590
  {
591
  "date" : "<?php the_time('d') ?><?php the_time('m') ?><?php the_time('Y') ?>",
@@ -596,11 +682,14 @@ function edcal_postJSON($post, $addComma = true, $fullPost = false) {
596
  "status" : "<?php echo(get_post_status()); ?>",
597
  "title" : <?php echo(edcal_json_encode(get_the_title())); ?>,
598
  "author" : "<?php the_author(); ?>",
 
 
 
599
  <?php if ( current_user_can('edit_post', $post->ID) ) {?>
600
  "editlink" : "<?php echo(get_edit_post_link($id)); ?>",
601
  <?php } ?>
602
 
603
- <?php if ( current_user_can('delete_post', $post->ID) ) { // [wes] changed delete link to edcal ajax link ?>
604
  "dellink" : "javascript:edcal.deletePost(<?php echo $post->ID ?>)",
605
  <?php } ?>
606
 
@@ -618,8 +707,7 @@ function edcal_postJSON($post, $addComma = true, $fullPost = false) {
618
  }
619
  }
620
 
621
-
622
- /* [wes]
623
  * This is a helper AJAX function to delete a post. It gets called
624
  * when a user clicks the delete button, and allows the user to
625
  * retain their position within the calendar without a page refresh.
@@ -795,6 +883,15 @@ function edcal_savepost() {
795
  $my_post['post_modified'] = $edcal_date;
796
  $my_post['post_modified_gmt'] = get_gmt_from_date($edcal_date);
797
 
 
 
 
 
 
 
 
 
 
798
  if($_POST['status']) {
799
  wp_transition_post_status($_POST['status'], $my_post['post_status'], $my_post);
800
  $my_post['post_status'] = $_POST['status'];
@@ -802,16 +899,24 @@ function edcal_savepost() {
802
 
803
 
804
  // Insert the post into the database
805
- if($my_post['ID'])
806
  $my_post_id = wp_update_post( $my_post );
807
- else
808
- $my_post_id = wp_insert_post( $my_post );
 
809
 
810
  // TODO: throw error if update/insert or getsinglepost fails
811
  /*
812
  * We finish by returning the latest data for the post in the JSON
813
  */
814
- $post = query_posts( array('p' => $my_post_id) );
 
 
 
 
 
 
 
815
 
816
  // get_post and setup_postdata don't get along, so we're doing a mini-loop
817
  if(have_posts()) :
18
  /*
19
  Plugin Name: WordPress Editorial Calendar
20
  Description: The Editorial Calendar makes it possible to see all your posts and drag and drop them to manage your blog.
21
+ Version: 1.3
22
  Author: Colin Vernon, Justin Evans, Mary Vogt, and Zack Grossbart
23
  Author URI: http://www.zackgrossbart.com
24
  Plugin URI: http://stresslimitdesign.com/editorial-calendar-plugin
51
  */
52
  $EDCAL_NONCE_ERROR = "6";
53
 
54
+ /*
55
+ * This boolean variable will be used to check whether this
56
+ * installation of WordPress supports custom post types.
57
+ */
58
+ $edcal_supports_custom_types = function_exists('get_post_types');
59
+
60
  function edcal_load_language() {
61
  $plugin_dir = basename(dirname(__FILE__));
62
  load_plugin_textdomain( 'editorial-calendar', 'wp-content/plugins/' . $plugin_dir . '/languages/', $plugin_dir . '/languages/' );
66
  * This function adds our calendar page to the admin UI
67
  */
68
  function edcal_list_add_management_page( ) {
69
+ global $edcal_supports_custom_types;
70
  if ( function_exists('add_management_page') ) {
71
  $page = add_posts_page( __('Calendar', 'editorial-calendar'), __('Calendar', 'editorial-calendar'), 'edit_posts', 'cal', 'edcal_list_admin' );
72
  add_action( "admin_print_scripts-$page", 'edcal_scripts' );
73
+
74
+ if($edcal_supports_custom_types) {
75
+
76
+ /*
77
+ * We add one calendar for Posts and then we add a separate calendar for each
78
+ * custom post type. This calendar will have an URL like this:
79
+ * /wp-admin/edit.php?post_type=podcasts&page=cal_podcasts
80
+ *
81
+ * We can then use the post_type parameter to show the posts of just that custom
82
+ * type and update the labels for each post type.
83
+ */
84
+ $args = array(
85
+ 'public' => true,
86
+ '_builtin' => false
87
+ );
88
+ $output = 'names'; // names or objects
89
+ $operator = 'and'; // 'and' or 'or'
90
+ $post_types = get_post_types($args,$output,$operator);
91
+
92
+ foreach ($post_types as $post_type) {
93
+ $page = add_submenu_page('edit.php?post_type=' . $post_type, __('Calendar', 'editorial-calendar'), __('Calendar', 'editorial-calendar'), 'edit_posts', 'cal_' . $post_type, 'edcal_list_admin');
94
+ add_action( "admin_print_scripts-$page", 'edcal_scripts' );
95
+ }
96
+
97
+ }
98
  }
99
  }
100
 
226
  * pass the values to JavaScript.
227
  */
228
 
229
+ edcal.str_by = <?php echo(edcal_json_encode(__('%1$s by %2$s', 'editorial-calendar'))) ?>;
230
+
 
 
231
  edcal.str_addPostLink = <?php echo(edcal_json_encode(__('New Post', 'editorial-calendar'))) ?>;
232
 
233
  edcal.str_draft = <?php echo(edcal_json_encode(__(' [DRAFT]', 'editorial-calendar'))) ?>;
245
  edcal.str_posttitle = <?php echo(edcal_json_encode(__('Title', 'editorial-calendar'))) ?>;
246
  edcal.str_postcontent = <?php echo(edcal_json_encode(__('Content', 'editorial-calendar'))) ?>;
247
  edcal.str_newpost = <?php echo(edcal_json_encode(__('Add a new post on ', 'editorial-calendar'))) ?>;
248
+ edcal.str_newpost_title = <?php echo(edcal_json_encode(sprintf(__('New %s - ', 'editorial-calendar'), edcal_get_posttype_singlename()))) ?> ;
249
  edcal.str_update = <?php echo(edcal_json_encode(__('Update', 'editorial-calendar'))) ?>;
250
  edcal.str_publish = <?php echo(edcal_json_encode(__('Schedule', 'editorial-calendar'))) ?>;
251
  edcal.str_review = <?php echo(edcal_json_encode(__('Submit for Review', 'editorial-calendar'))) ?>;
252
  edcal.str_save = <?php echo(edcal_json_encode(__('Save', 'editorial-calendar'))) ?>;
253
+ edcal.str_edit_post_title = <?php echo(edcal_json_encode(__('Edit %1$s - %2$s', 'editorial-calendar'))) ?>;
254
  edcal.str_scheduled = <?php echo(edcal_json_encode(__('Scheduled', 'editorial-calendar'))) ?>;
255
 
256
  edcal.str_del_msg1 = <?php echo(edcal_json_encode(__('You are about to delete the post "', 'editorial-calendar'))) ?>;
323
 
324
  <div class="wrap">
325
  <div class="icon32" id="icon-edit"><br/></div>
326
+ <h2 id="edcal_main_title"><?php echo(edcal_get_posttype_multiplename()); ?><?php echo(__(' Calendar', 'editorial-calendar')); ?></h2>
327
 
328
  <div id="loadingcont">
329
  <div id="loading"> </div>
504
  if (!edcal_checknonce()) {
505
  die();
506
  }
507
+
508
  global $edcal_startDate, $edcal_endDate;
509
  $edcal_startDate = isset($_GET['from'])?$_GET['from']:null;
510
  $edcal_endDate = isset($_GET['to'])?$_GET['to']:null;
512
  $args = array(
513
  'posts_per_page' => -1,
514
  'post_status' => "publish&future&draft",
515
+ 'post_parent' => null // any parent
 
516
  );
517
 
518
+ /*
519
+ * If we're in the specific post type case we need to add
520
+ * the post type to our query.
521
+ */
522
+ $post_type = $_GET['post_type'];
523
+ if ($post_type) {
524
+ $args['post_type'] = $post_type;
525
+ }
526
+
527
  add_filter('posts_where', 'edcal_filter_where');
528
  $myposts = query_posts($args);
529
  remove_filter('posts_where', 'edcal_filter_where');
533
  $size = sizeof($myposts);
534
 
535
  for($i = 0; $i < $size; $i++) {
 
 
 
 
 
 
 
 
536
  $post = $myposts[$i];
537
+ edcal_postJSON($post, $i < $size - 1);
 
 
 
538
  }
539
 
540
  ?> ]
558
 
559
  // If a proper post_id wasn't passed, return
560
  if(!$post_id) die();
561
+
562
+ $args = array(
563
+ 'post__in' => array($post_id)
564
+ );
565
+
566
+ /*
567
+ * If we're in the specific post type case we need to add
568
+ * the post type to our query.
569
+ */
570
+ $post_type = $_GET['post_type'];
571
+ if ($post_type) {
572
+ $args['post_type'] = $post_type;
573
+ }
574
 
575
+ $post = query_posts($args);
576
+
577
  // get_post and setup_postdata don't get along, so we're doing a mini-loop
578
  if(have_posts()) :
579
  while(have_posts()) : the_post();
601
  return json_encode(str_replace("&#039;", "&#146;", $string));
602
  }
603
 
604
+ /*
605
+ * This helper functions gets the plural name of the post
606
+ * type specified by the post_type parameter.
607
+ */
608
+ function edcal_get_posttype_multiplename() {
609
+
610
+ $post_type = $_GET['post_type'];
611
+ if (!$post_type) {
612
+ return 'Posts';
613
+ }
614
+
615
+ $postTypeObj = get_post_type_object($post_type);
616
+ return $postTypeObj->labels->name;
617
+ }
618
+
619
+ /*
620
+ * This helper functions gets the singular name of the post
621
+ * type specified by the post_type parameter.
622
+ */
623
+
624
+ function edcal_get_posttype_singlename() {
625
+
626
+ $post_type = $_GET['post_type'];
627
+ if (!$post_type) {
628
+ return 'Post';
629
+ }
630
+
631
+ $postTypeObj = get_post_type_object($post_type);
632
+ return $postTypeObj->labels->singular_name;
633
+ }
634
+
635
  /*
636
  * This function sets up the post data and prints out the values we
637
  * care about in a JSON data structure. This prints out just the
638
  * value part. If $fullPost is set to true, post_content is also returned.
639
  */
640
  function edcal_postJSON($post, $addComma = true, $fullPost = false) {
641
+ global $edcal_supports_custom_types;
642
  $timeFormat = get_option("time_format");
643
  if ($timeFormat == "g:i a") {
644
  $timeFormat = "ga";
658
  return;
659
  }
660
 
661
+ /*
662
+ * We want to return the type of each post as part of the
663
+ * JSON data about that post. Right now this will always
664
+ * match the post_type parameter for the calendar, but in
665
+ * the future we might support a mixed post type calendar
666
+ * and this extra data will become useful. Right now we
667
+ * are using this data for the title on the quick edit form.
668
+ */
669
+ if($edcal_supports_custom_types) {
670
+ $postTypeObj = get_post_type_object(get_post_type( $post ));
671
+ $postTypeTitle = $postTypeObj->labels->singular_name;
672
+ } else {
673
+ $postTypeTitle = 'post';
674
+ }
675
  ?>
676
  {
677
  "date" : "<?php the_time('d') ?><?php the_time('m') ?><?php the_time('Y') ?>",
682
  "status" : "<?php echo(get_post_status()); ?>",
683
  "title" : <?php echo(edcal_json_encode(get_the_title())); ?>,
684
  "author" : "<?php the_author(); ?>",
685
+ "type" : "<?php echo(get_post_type( $post )); ?>",
686
+ "typeTitle" : "<?php echo($postTypeTitle); ?>",
687
+
688
  <?php if ( current_user_can('edit_post', $post->ID) ) {?>
689
  "editlink" : "<?php echo(get_edit_post_link($id)); ?>",
690
  <?php } ?>
691
 
692
+ <?php if ( current_user_can('delete_post', $post->ID) ) {?>
693
  "dellink" : "javascript:edcal.deletePost(<?php echo $post->ID ?>)",
694
  <?php } ?>
695
 
707
  }
708
  }
709
 
710
+ /*
 
711
  * This is a helper AJAX function to delete a post. It gets called
712
  * when a user clicks the delete button, and allows the user to
713
  * retain their position within the calendar without a page refresh.
883
  $my_post['post_modified'] = $edcal_date;
884
  $my_post['post_modified_gmt'] = get_gmt_from_date($edcal_date);
885
 
886
+ /*
887
+ * When we create a new post we need to specify the post type
888
+ * passed in from the JavaScript.
889
+ */
890
+ $post_type = isset($_POST["post_type"])?$_POST["post_type"]:null;
891
+ if ($post_type) {
892
+ $my_post['post_type'] = $post_type;
893
+ }
894
+
895
  if($_POST['status']) {
896
  wp_transition_post_status($_POST['status'], $my_post['post_status'], $my_post);
897
  $my_post['post_status'] = $_POST['status'];
899
 
900
 
901
  // Insert the post into the database
902
+ if($my_post['ID']) {
903
  $my_post_id = wp_update_post( $my_post );
904
+ } else {
905
+ $my_post_id = wp_insert_post( $my_post );
906
+ }
907
 
908
  // TODO: throw error if update/insert or getsinglepost fails
909
  /*
910
  * We finish by returning the latest data for the post in the JSON
911
  */
912
+ $args = array(
913
+ 'p' => $my_post_id
914
+ );
915
+
916
+ if ($post_type) {
917
+ $args['post_type'] = $post_type;
918
+ }
919
+ $post = query_posts($args);
920
 
921
  // get_post and setup_postdata don't get along, so we're doing a mini-loop
922
  if(have_posts()) :
edcal_test.js CHANGED
@@ -19,137 +19,139 @@
19
  */
20
 
21
  var edcal_test = {
22
-
23
  post: {},
24
-
25
  testContent: 'This is the content of the unit test post.',
26
-
27
-
28
  runTests: function() {
29
- jQuery("head").append("<link>");
30
- css = jQuery("head").children(":last");
31
  css.attr({
32
- rel: "stylesheet",
33
- type: "text/css",
34
- href: "../wp-content/plugins/edcal/lib/qunit.css"
35
  });
36
 
37
- jQuery("#wpbody-content .wrap").append('<div id="edcal-qunit"></div>');
38
 
39
- jQuery("#edcal-qunit").append('<h1 id="qunit-header">WordPress Editorial Calendar Unit Tests</h1>' +
40
  '<h2 id="qunit-banner"></h2>' +
 
41
  '<h2 id="qunit-userAgent"></h2>' +
42
- '<ol id="qunit-tests"></ol>');
 
43
 
44
 
45
  edcal_test.moveTests();
46
  },
47
 
48
  getFirstDate: function() {
49
- var api = jQuery("#edcal_scrollable").scrollable();
50
  var items = api.getVisibleItems();
51
 
52
- return edcal.getDayFromDayId(items.eq(0).children(".row").children(".day:first").attr("id"));
53
  },
54
 
55
  getLastDate: function() {
56
- var api = jQuery("#edcal_scrollable").scrollable();
57
  var items = api.getVisibleItems();
58
 
59
- return edcal.getDayFromDayId(items.eq(edcal.weeksPref - 1).children(".row").children(".day:last").attr("id"));
60
  },
61
 
62
  moveTests: function() {
63
  var curSunday = edcal.nextStartOfWeek(Date.today()).add(-1).weeks();
64
 
65
  edcal.moveTo(Date.today());
66
-
67
  /*
68
  * We'll start of with a series of tests about moving the calendar around
69
  */
70
- test("Move to today and check visible dates", function() {
71
  expect(2);
72
- ok(edcal_test.getFirstDate().equals(curSunday.clone()), "firstDate should match " + curSunday);
73
 
74
- ok(edcal_test.getLastDate().equals(curSunday.clone().add(edcal.weeksPref).weeks().add(-1).days()),
75
- "lastDate should match " + curSunday);
76
  });
77
 
78
- asyncTest("Move 1 week in the future and check visible dates", function() {
79
  expect(2);
80
  edcal.move(1, true, function() {
81
- ok(edcal_test.getFirstDate().equals(curSunday.clone().add(1).weeks()), "firstDate should match " + curSunday );
 
 
 
82
 
83
- ok(edcal_test.getLastDate().equals(curSunday.clone().add(edcal.weeksPref).weeks().add(-1).days().add(1).weeks()),
84
- "lastDate should match " + curSunday );
85
-
86
  edcal.move(1, false, function() {
87
  start();
88
  edcal_test.testMoveFourWeeks();
89
  });
90
  });
91
  });
92
-
93
  return;
94
-
95
  },
96
-
97
  testMoveFourWeeks: function() {
98
  var curSunday = edcal.nextStartOfWeek(Date.today()).add(-1).weeks();
99
-
100
  /*
101
  * Now we'll move 4 weeks into the future
102
  */
103
- asyncTest("Move 4 week in the future and check visible dates", function() {
104
  expect(2);
105
-
106
  edcal.move(4, true, function() {
107
- ok(edcal_test.getFirstDate().equals(curSunday.clone().add(4).weeks()), "firstDate should match " + curSunday );
 
 
 
108
 
109
- ok(edcal_test.getLastDate().equals(curSunday.clone().add(edcal.weeksPref).weeks().add(-1).days().add(4).weeks()),
110
- "lastDate should match " + curSunday );
111
-
112
  edcal.move(4, false, function() {
113
  start();
114
  edcal_test.testMoveEightWeeks();
115
  });
116
  });
117
-
118
-
119
  });
120
  },
121
-
122
  testMoveEightWeeks: function() {
123
  var curSunday = edcal.nextStartOfWeek(Date.today()).add(-1).weeks();
124
-
125
  /*
126
  * Now 8 weeks into the past
127
  */
128
- asyncTest("Move 8 week in the past and check visible dates", function() {
129
  expect(2);
130
-
131
  edcal.move(8, false, function() {
132
- ok(edcal_test.getFirstDate().equals(curSunday.clone().add(-8).weeks()), "firstDate should match " + curSunday );
 
 
 
133
 
134
- ok(edcal_test.getLastDate().equals(curSunday.clone().add(edcal.weeksPref).weeks().add(-1).days().add(-8).weeks()),
135
- "lastDate should match " + curSunday );
136
-
137
  edcal.move(8, true, function() {
138
  start();
139
  edcal_test.testCreatePost();
140
  });
141
  });
142
-
143
-
144
  });
145
  },
146
-
147
  testCreatePost: function() {
148
  /*
149
  * Now we'll do a few tests about creating, modifying, and deleting posts.
150
  */
151
 
152
- asyncTest("Create a new post", function() {
153
  expect(3);
154
 
155
  edcal_test.post.title = 'Unit Test Post';
@@ -158,150 +160,150 @@ var edcal_test = {
158
  edcal_test.post.time = '10:00 AM';
159
  edcal_test.post.date = Date.today().add(7).days().toString(edcal.internalDateFormat);
160
  edcal_test.post.id = '0';
161
-
162
  edcal.savePost(edcal_test.post, false, false, function(res) {
163
  if (!res.post) {
164
- ok(false, "There was an error creating the new post.");
165
  start();
166
  return;
167
  }
168
-
169
- equals(res.post.date, edcal_test.post.date, "The resulting post should have the same date as the request");
170
- equals(res.post.title, edcal_test.post.title, "The resulting post should have the same title as the request");
171
-
172
- equals(jQuery('#post-' + res.post.id).length, 1, "The post should be added in only one place in the calendar.");
173
-
174
  edcal_test.post = res.post;
175
-
176
  start();
177
-
178
  edcal_test.testGetPost();
179
  });
180
  });
181
-
182
  },
183
-
184
  testGetPost: function() {
185
  /*
186
  * We'll start by getting data about the post we've just created
187
  */
188
 
189
- asyncTest("Get post information", function() {
190
  expect(2);
191
 
192
  edcal.getPost(edcal_test.post.id, function(post) {
193
- equals(post.date, edcal_test.post.date, "The resulting post should have the same date as the request");
194
- equals(post.title, edcal_test.post.title, "The resulting post should have the same title as the request");
195
-
196
  edcal_test.post = post;
197
-
198
  start();
199
-
200
  edcal_test.testMovePost();
201
  });
202
  });
203
-
204
  },
205
 
206
  testMovePost: function() {
207
 
208
- asyncTest("Change the date of an existing post", function() {
209
  expect(2);
210
 
211
- // We added the post one week in the future, now we will move it
212
  // one day after that.
213
  var newDate = Date.today().add(8).days().toString(edcal.internalDateFormat);
214
 
215
  edcal.doDrop(edcal_test.post.date, 'post-' + edcal_test.post.id, newDate, function(res) {
216
-
217
  if (!res.post) {
218
- ok(false, "There was an error creating the new post.");
219
  return;
220
  }
221
-
222
- equals(res.post.date, newDate, "The resulting post should have the same date as the request");
223
-
224
- equals(jQuery('#post-' + res.post.id).length, 1, "The post should be added in only one place in the calendar.");
225
-
226
  edcal_test.post = res.post;
227
-
228
  start();
229
-
230
  edcal_test.testMovePostOneWeek();
231
  });
232
  });
233
-
234
  },
235
-
236
  testMovePostOneWeek: function() {
237
 
238
- asyncTest("Make a second change to the date of an existing post", function() {
239
  expect(2);
240
 
241
- // We added the post one week in the future, now we will move it
242
  // one day after that.
243
  var newDate = Date.today().add(22).days().toString(edcal.internalDateFormat);
244
 
245
  edcal.doDrop(edcal_test.post.date, 'post-' + edcal_test.post.id, newDate, function(res) {
246
-
247
  if (!res.post) {
248
- ok(false, "There was an error creating the new post.");
249
  return;
250
  }
251
-
252
- equals(res.post.date, newDate, "The resulting post should have the same date as the request");
253
-
254
- equals(jQuery('#post-' + res.post.id).length, 1, "The post should be added in only one place in the calendar.");
255
-
256
  edcal_test.post = res.post;
257
-
258
  start();
259
-
260
  edcal_test.testEditPost();
261
  });
262
  });
263
-
264
  },
265
-
266
  testEditPost: function() {
267
-
268
- asyncTest("Edit the content of an existing post and mark it as scheduled", function() {
269
  expect(2);
270
 
271
  edcal_test.post.title = 'Unit Test Post &#8211 Changed';
272
  edcal_test.post.content = 'This is the content of the unit test post. &#8211 Changed';
273
-
274
  edcal.savePost(edcal_test.post, false, true, function(res)
275
  {
276
  if (!res.post) {
277
- ok(false, "There was an error editing the post.");
278
  start();
279
  return;
280
  }
281
 
282
- equals(res.post.title, edcal_test.post.title, "The resulting post should have the same title as the request");
283
 
284
- equals(jQuery('#post-' + res.post.id).length, 1, "The post should be added in only one place in the calendar.");
285
 
286
  edcal_test.post = res.post;
287
-
288
  start();
289
-
290
  edcal_test.testDateConflict();
291
 
292
  });
293
  });
294
-
295
  },
296
-
297
  testDateConflict: function() {
298
- asyncTest("Try to change a post date and fail because of a concurrency conflict", function() {
299
  expect(2);
300
 
301
  edcal_test.post.date = Date.today().add(-1).days().toString(edcal.internalDateFormat);
302
-
303
  /*
304
- * We added the post one week in the future, now we will move it
305
  * one day after that.
306
  */
307
  var newDate = Date.today().add(8).days().toString(edcal.internalDateFormat);
@@ -309,43 +311,43 @@ var edcal_test = {
309
  edcal.changeDate(newDate, edcal_test.post, function(res)
310
  {
311
  if (!res.post) {
312
- ok(false, "There was an error with the change date conflict.");
313
  return;
314
  }
315
 
316
- equals(res.error, edcal.CONCURRENCY_ERROR, "This move should show an exception because it is in conflict.");
317
 
318
- equals(jQuery('#post-' + res.post.id).length, 1, "The post should be added in only one place in the calendar.");
319
 
320
  edcal_test.post = res.post;
321
-
322
  start();
323
-
324
  edcal_test.testDeletePost();
325
 
326
  });
327
  });
328
-
329
  },
330
-
331
  testDeletePost: function() {
332
-
333
  /*
334
  * The last step is to delete the post we made so
335
  * the test cleans up after itself.
336
  */
337
- asyncTest("Delete the post created for testing", function() {
338
  expect(1);
339
 
340
  edcal.deletePost(edcal_test.post.id, function(res)
341
  {
342
  if (!res.post) {
343
- ok(false, "There was an error creating the new post.");
344
  start();
345
  return;
346
  }
347
 
348
- equals(jQuery('#post-' + res.post.id).length, 0, "The post should now be deleted from the calendar.");
349
  start();
350
 
351
  });
19
  */
20
 
21
  var edcal_test = {
22
+
23
  post: {},
24
+
25
  testContent: 'This is the content of the unit test post.',
26
+
27
+
28
  runTests: function() {
29
+ jQuery('head').append('<link>');
30
+ css = jQuery('head').children(':last');
31
  css.attr({
32
+ rel: 'stylesheet',
33
+ type: 'text/css',
34
+ href: '../wp-content/plugins/edcal/lib/qunit.css'
35
  });
36
 
37
+ jQuery('#wpbody-content .wrap').append('<div id="edcal-qunit"></div>');
38
 
39
+ jQuery('#edcal-qunit').append('<h1 id="qunit-header">WordPress Editorial Calendar Unit Tests</h1>' +
40
  '<h2 id="qunit-banner"></h2>' +
41
+ '<div id="qunit-testrunner-toolbar"></div>' +
42
  '<h2 id="qunit-userAgent"></h2>' +
43
+ '<ol id="qunit-tests"></ol>' +
44
+ '<div id="qunit-fixture">test markup</div>');
45
 
46
 
47
  edcal_test.moveTests();
48
  },
49
 
50
  getFirstDate: function() {
51
+ var api = jQuery('#edcal_scrollable').scrollable();
52
  var items = api.getVisibleItems();
53
 
54
+ return edcal.getDayFromDayId(items.eq(0).children('.row').children('.day:first').attr('id'));
55
  },
56
 
57
  getLastDate: function() {
58
+ var api = jQuery('#edcal_scrollable').scrollable();
59
  var items = api.getVisibleItems();
60
 
61
+ return edcal.getDayFromDayId(items.eq(edcal.weeksPref - 1).children('.row').children('.day:last').attr('id'));
62
  },
63
 
64
  moveTests: function() {
65
  var curSunday = edcal.nextStartOfWeek(Date.today()).add(-1).weeks();
66
 
67
  edcal.moveTo(Date.today());
68
+
69
  /*
70
  * We'll start of with a series of tests about moving the calendar around
71
  */
72
+ test('Move to today and check visible dates', function() {
73
  expect(2);
74
+ ok(edcal_test.getFirstDate().equals(curSunday.clone()), 'firstDate should match ' + curSunday);
75
 
76
+ ok(edcal_test.getLastDate().equals(curSunday.clone().add(edcal.weeksPref).weeks().add(-1).days()),
77
+ 'lastDate should match ' + curSunday);
78
  });
79
 
80
+ asyncTest('Move 1 week in the future and check visible dates', function() {
81
  expect(2);
82
  edcal.move(1, true, function() {
83
+ ok(edcal_test.getFirstDate().equals(curSunday.clone().add(1).weeks()), 'firstDate should match ' + curSunday);
84
+
85
+ ok(edcal_test.getLastDate().equals(curSunday.clone().add(edcal.weeksPref).weeks().add(-1).days().add(1).weeks()),
86
+ 'lastDate should match ' + curSunday);
87
 
 
 
 
88
  edcal.move(1, false, function() {
89
  start();
90
  edcal_test.testMoveFourWeeks();
91
  });
92
  });
93
  });
94
+
95
  return;
96
+
97
  },
98
+
99
  testMoveFourWeeks: function() {
100
  var curSunday = edcal.nextStartOfWeek(Date.today()).add(-1).weeks();
101
+
102
  /*
103
  * Now we'll move 4 weeks into the future
104
  */
105
+ asyncTest('Move 4 week in the future and check visible dates', function() {
106
  expect(2);
107
+
108
  edcal.move(4, true, function() {
109
+ ok(edcal_test.getFirstDate().equals(curSunday.clone().add(4).weeks()), 'firstDate should match ' + curSunday);
110
+
111
+ ok(edcal_test.getLastDate().equals(curSunday.clone().add(edcal.weeksPref).weeks().add(-1).days().add(4).weeks()),
112
+ 'lastDate should match ' + curSunday);
113
 
 
 
 
114
  edcal.move(4, false, function() {
115
  start();
116
  edcal_test.testMoveEightWeeks();
117
  });
118
  });
119
+
120
+
121
  });
122
  },
123
+
124
  testMoveEightWeeks: function() {
125
  var curSunday = edcal.nextStartOfWeek(Date.today()).add(-1).weeks();
126
+
127
  /*
128
  * Now 8 weeks into the past
129
  */
130
+ asyncTest('Move 8 week in the past and check visible dates', function() {
131
  expect(2);
132
+
133
  edcal.move(8, false, function() {
134
+ ok(edcal_test.getFirstDate().equals(curSunday.clone().add(-8).weeks()), 'firstDate should match ' + curSunday);
135
+
136
+ ok(edcal_test.getLastDate().equals(curSunday.clone().add(edcal.weeksPref).weeks().add(-1).days().add(-8).weeks()),
137
+ 'lastDate should match ' + curSunday);
138
 
 
 
 
139
  edcal.move(8, true, function() {
140
  start();
141
  edcal_test.testCreatePost();
142
  });
143
  });
144
+
145
+
146
  });
147
  },
148
+
149
  testCreatePost: function() {
150
  /*
151
  * Now we'll do a few tests about creating, modifying, and deleting posts.
152
  */
153
 
154
+ asyncTest('Create a new post', function() {
155
  expect(3);
156
 
157
  edcal_test.post.title = 'Unit Test Post';
160
  edcal_test.post.time = '10:00 AM';
161
  edcal_test.post.date = Date.today().add(7).days().toString(edcal.internalDateFormat);
162
  edcal_test.post.id = '0';
163
+
164
  edcal.savePost(edcal_test.post, false, false, function(res) {
165
  if (!res.post) {
166
+ ok(false, 'There was an error creating the new post.');
167
  start();
168
  return;
169
  }
170
+
171
+ equals(res.post.date, edcal_test.post.date, 'The resulting post should have the same date as the request');
172
+ equals(res.post.title, edcal_test.post.title, 'The resulting post should have the same title as the request');
173
+
174
+ equals(jQuery('#post-' + res.post.id).length, 1, 'The post should be added in only one place in the calendar.');
175
+
176
  edcal_test.post = res.post;
177
+
178
  start();
179
+
180
  edcal_test.testGetPost();
181
  });
182
  });
183
+
184
  },
185
+
186
  testGetPost: function() {
187
  /*
188
  * We'll start by getting data about the post we've just created
189
  */
190
 
191
+ asyncTest('Get post information', function() {
192
  expect(2);
193
 
194
  edcal.getPost(edcal_test.post.id, function(post) {
195
+ equals(post.date, edcal_test.post.date, 'The resulting post should have the same date as the request');
196
+ equals(post.title, edcal_test.post.title, 'The resulting post should have the same title as the request');
197
+
198
  edcal_test.post = post;
199
+
200
  start();
201
+
202
  edcal_test.testMovePost();
203
  });
204
  });
205
+
206
  },
207
 
208
  testMovePost: function() {
209
 
210
+ asyncTest('Change the date of an existing post', function() {
211
  expect(2);
212
 
213
+ // We added the post one week in the future, now we will move it
214
  // one day after that.
215
  var newDate = Date.today().add(8).days().toString(edcal.internalDateFormat);
216
 
217
  edcal.doDrop(edcal_test.post.date, 'post-' + edcal_test.post.id, newDate, function(res) {
218
+
219
  if (!res.post) {
220
+ ok(false, 'There was an error creating the new post.');
221
  return;
222
  }
223
+
224
+ equals(res.post.date, newDate, 'The resulting post should have the same date as the request');
225
+
226
+ equals(jQuery('#post-' + res.post.id).length, 1, 'The post should be added in only one place in the calendar.');
227
+
228
  edcal_test.post = res.post;
229
+
230
  start();
231
+
232
  edcal_test.testMovePostOneWeek();
233
  });
234
  });
235
+
236
  },
237
+
238
  testMovePostOneWeek: function() {
239
 
240
+ asyncTest('Make a second change to the date of an existing post', function() {
241
  expect(2);
242
 
243
+ // We added the post one week in the future, now we will move it
244
  // one day after that.
245
  var newDate = Date.today().add(22).days().toString(edcal.internalDateFormat);
246
 
247
  edcal.doDrop(edcal_test.post.date, 'post-' + edcal_test.post.id, newDate, function(res) {
248
+
249
  if (!res.post) {
250
+ ok(false, 'There was an error creating the new post.');
251
  return;
252
  }
253
+
254
+ equals(res.post.date, newDate, 'The resulting post should have the same date as the request');
255
+
256
+ equals(jQuery('#post-' + res.post.id).length, 1, 'The post should be added in only one place in the calendar.');
257
+
258
  edcal_test.post = res.post;
259
+
260
  start();
261
+
262
  edcal_test.testEditPost();
263
  });
264
  });
265
+
266
  },
267
+
268
  testEditPost: function() {
269
+
270
+ asyncTest('Edit the content of an existing post and mark it as scheduled', function() {
271
  expect(2);
272
 
273
  edcal_test.post.title = 'Unit Test Post &#8211 Changed';
274
  edcal_test.post.content = 'This is the content of the unit test post. &#8211 Changed';
275
+
276
  edcal.savePost(edcal_test.post, false, true, function(res)
277
  {
278
  if (!res.post) {
279
+ ok(false, 'There was an error editing the post.');
280
  start();
281
  return;
282
  }
283
 
284
+ equals(res.post.title, edcal_test.post.title, 'The resulting post should have the same title as the request');
285
 
286
+ equals(jQuery('#post-' + res.post.id).length, 1, 'The post should be added in only one place in the calendar.');
287
 
288
  edcal_test.post = res.post;
289
+
290
  start();
291
+
292
  edcal_test.testDateConflict();
293
 
294
  });
295
  });
296
+
297
  },
298
+
299
  testDateConflict: function() {
300
+ asyncTest('Try to change a post date and fail because of a concurrency conflict', function() {
301
  expect(2);
302
 
303
  edcal_test.post.date = Date.today().add(-1).days().toString(edcal.internalDateFormat);
304
+
305
  /*
306
+ * We added the post one week in the future, now we will move it
307
  * one day after that.
308
  */
309
  var newDate = Date.today().add(8).days().toString(edcal.internalDateFormat);
311
  edcal.changeDate(newDate, edcal_test.post, function(res)
312
  {
313
  if (!res.post) {
314
+ ok(false, 'There was an error with the change date conflict.');
315
  return;
316
  }
317
 
318
+ equals(res.error, edcal.CONCURRENCY_ERROR, 'This move should show an exception because it is in conflict.');
319
 
320
+ equals(jQuery('#post-' + res.post.id).length, 1, 'The post should be added in only one place in the calendar.');
321
 
322
  edcal_test.post = res.post;
323
+
324
  start();
325
+
326
  edcal_test.testDeletePost();
327
 
328
  });
329
  });
330
+
331
  },
332
+
333
  testDeletePost: function() {
334
+
335
  /*
336
  * The last step is to delete the post we made so
337
  * the test cleans up after itself.
338
  */
339
+ asyncTest('Delete the post created for testing', function() {
340
  expect(1);
341
 
342
  edcal.deletePost(edcal_test.post.id, function(res)
343
  {
344
  if (!res.post) {
345
+ ok(false, 'There was an error creating the new post.');
346
  start();
347
  return;
348
  }
349
 
350
+ equals(jQuery('#post-' + res.post.id).length, 0, 'The post should now be deleted from the calendar.');
351
  start();
352
 
353
  });
languages/editorial-calendar-pt_BR.mo ADDED
Binary file
languages/editorial-calendar-pt_BR.po ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2010
2
+ # This file is distributed under the same license as the package.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: \n"
6
+ "Report-Msgid-Bugs-To: http://wordpress.org/tag/editorial-calendar\n"
7
+ "POT-Creation-Date: 2011-01-03 12:24:41+00:00\n"
8
+ "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=UTF-8\n"
10
+ "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2011-01-03 08:56-0500\n"
12
+ "Last-Translator: Zack Grossbart <zack@grossbart.com>\n"
13
+ "Language-Team: LANGUAGE <LL@li.org>\n"
14
+
15
+ #: edcal.php:71
16
+ #: edcal.php:93
17
+ msgid "Calendar"
18
+ msgstr "Calendário"
19
+
20
+ #: edcal.php:221
21
+ #: edcal.php:465
22
+ msgid "en-US"
23
+ msgstr "pt-BR"
24
+
25
+ #: edcal.php:229
26
+ msgid "%1$s by %2$s"
27
+ msgstr "%1$s por %2$s"
28
+
29
+ #: edcal.php:231
30
+ msgid "New Post"
31
+ msgstr "Novo Post"
32
+
33
+ #: edcal.php:233
34
+ msgid " [DRAFT]"
35
+ msgstr "[RASCUNHO]"
36
+
37
+ #: edcal.php:234
38
+ msgid " [PENDING]"
39
+ msgstr "[PENDENTE]"
40
+
41
+ #: edcal.php:235
42
+ msgid " [STICKY]"
43
+ msgstr "[FIXO]"
44
+
45
+ #: edcal.php:236
46
+ msgid " [DRAFT, STICKY]"
47
+ msgstr "[RASCUNHO, FIXO]"
48
+
49
+ #: edcal.php:237
50
+ msgid " [PENDING, STICKY]"
51
+ msgstr "[PENDENTE, FIXO]"
52
+
53
+ #: edcal.php:238
54
+ #: edcal.php:242
55
+ msgid "Edit"
56
+ msgstr "Editar"
57
+
58
+ #: edcal.php:239
59
+ msgid "Quick Edit"
60
+ msgstr "Ed Rápida"
61
+
62
+ #: edcal.php:240
63
+ msgid "Delete"
64
+ msgstr "Deletar"
65
+
66
+ #: edcal.php:241
67
+ msgid "View"
68
+ msgstr "Ver"
69
+
70
+ #: edcal.php:243
71
+ msgid "Status:"
72
+ msgstr "Estado:"
73
+
74
+ #: edcal.php:244
75
+ #: edcal.php:409
76
+ msgid "Cancel"
77
+ msgstr "Cancelar"
78
+
79
+ #: edcal.php:245
80
+ #: edcal.php:363
81
+ msgid "Title"
82
+ msgstr "Título"
83
+
84
+ #: edcal.php:246
85
+ #: edcal.php:368
86
+ msgid "Content"
87
+ msgstr "Conteúdo"
88
+
89
+ #: edcal.php:247
90
+ msgid "Add a new post on "
91
+ msgstr "Adicionar novo post em "
92
+
93
+ #: edcal.php:248
94
+ msgid "New %s - "
95
+ msgstr "Novo %s - "
96
+
97
+ #: edcal.php:249
98
+ msgid "Update"
99
+ msgstr "Atualizar"
100
+
101
+ #: edcal.php:250
102
+ #: edcal.php:408
103
+ msgid "Schedule"
104
+ msgstr "Agendar"
105
+
106
+ #: edcal.php:251
107
+ msgid "Submit for Review"
108
+ msgstr "Enviar para Revisão"
109
+
110
+ #: edcal.php:252
111
+ msgid "Save"
112
+ msgstr "Salvar"
113
+
114
+ #: edcal.php:253
115
+ msgid "Edit %1$s - %2$s"
116
+ msgstr "Editar %1$s - %2$s"
117
+
118
+ #: edcal.php:254
119
+ #: edcal.php:394
120
+ msgid "Scheduled"
121
+ msgstr "Agentado"
122
+
123
+ #: edcal.php:256
124
+ msgid "You are about to delete the post \""
125
+ msgstr "Você está prestes a deletar o post \""
126
+
127
+ #: edcal.php:257
128
+ msgid "\". Press Cancel to stop, OK to delete."
129
+ msgstr "\". Clique Cancelar para parar, OK para deletar."
130
+
131
+ #: edcal.php:259
132
+ msgid "Looks like someone else already moved this post."
133
+ msgstr "Parece que alguém já moveu este post."
134
+
135
+ #: edcal.php:260
136
+ msgid "You do not have permission to edit posts."
137
+ msgstr "Você não tem permissão para editar posts"
138
+
139
+ #: edcal.php:261
140
+ msgid "Invalid checksum for post. This is commonly a cross-site scripting error."
141
+ msgstr "Soma de verificação inválida para o post. Este é normalmente um erro de cross-site scripting."
142
+
143
+ #: edcal.php:262
144
+ msgid "There was an error contacting your blog."
145
+ msgstr "Ocorreu um erro contatando seu blog."
146
+
147
+ #: edcal.php:264
148
+ msgid "Screen Options"
149
+ msgstr "Opções de Tela"
150
+
151
+ #: edcal.php:265
152
+ msgid "Colors"
153
+ msgstr "Cores"
154
+
155
+ #: edcal.php:266
156
+ msgid "Drafts: "
157
+ msgstr "Rascunhos: "
158
+
159
+ #: edcal.php:267
160
+ msgid "Apply"
161
+ msgstr "Aplicar"
162
+
163
+ #: edcal.php:268
164
+ msgid "Show on screen"
165
+ msgstr "Exibir na tela"
166
+
167
+ #: edcal.php:269
168
+ msgid " weeks at a time"
169
+ msgstr " semanas de uma vez"
170
+
171
+ #: edcal.php:270
172
+ msgid "Show in Calendar Cell"
173
+ msgstr "Mostrar na Célula do Calendário"
174
+
175
+ #: edcal.php:271
176
+ msgid "Author"
177
+ msgstr "Autor"
178
+
179
+ #: edcal.php:272
180
+ #: edcal.php:388
181
+ msgid "Status"
182
+ msgstr "Estado"
183
+
184
+ #: edcal.php:273
185
+ msgid "Time of day"
186
+ msgstr "Hora do dia"
187
+
188
+ #: edcal.php:274
189
+ msgid "An error occurred while loading the calendar: "
190
+ msgstr "Ocorreu um erro carregando o calendário: "
191
+
192
+ #: edcal.php:276
193
+ msgid "The calendar can only show between 1 and 5 weeks at a time."
194
+ msgstr "O calendário só pode exibir entre 1 e 5 semanas de uma vez."
195
+
196
+ #: edcal.php:277
197
+ msgid "Select the number of weeks for the calendar to show."
198
+ msgstr "Selecione o número de semanas a exibir no calendário."
199
+
200
+ #: edcal.php:285
201
+ msgid "<h2>We're done</h2>We've finished collecting data. Thank you for helping us make the calendar better."
202
+ msgstr "<h2>Feito</h2>Acabamos a coleta de dados. Obrigado por nos ajudar a fazer o calendário melhor."
203
+
204
+ #: edcal.php:326
205
+ msgid " Calendar"
206
+ msgstr " - Calendário"
207
+
208
+ #: edcal.php:335
209
+ msgid "Jump back"
210
+ msgstr "Para trás"
211
+
212
+ #: edcal.php:337
213
+ msgid "Skip ahead"
214
+ msgstr "Para frente"
215
+
216
+ #: edcal.php:342
217
+ msgid "Scroll the calendar and make the today visible"
218
+ msgstr "Rolar o calendário e fazer 'hoje' visível"
219
+
220
+ #: edcal.php:342
221
+ msgid "Show Today"
222
+ msgstr "Mostrar Hoje"
223
+
224
+ #: edcal.php:354
225
+ msgid "Edit Post"
226
+ msgstr "Editar Post"
227
+
228
+ #: edcal.php:383
229
+ msgid "Time"
230
+ msgstr "Hora"
231
+
232
+ #: edcal.php:391
233
+ msgid "Draft"
234
+ msgstr "Rascunho"
235
+
236
+ #: edcal.php:392
237
+ msgid "Pending Review"
238
+ msgstr "Revisão Pendente"
239
+
240
+ #: edcal.php:734
241
+ #: edcal.php:737
242
+ msgid "Error in deleting..."
243
+ msgstr "Erro ao deletar..."
244
+
lib/edcallib.min.js CHANGED
@@ -1,59 +1,63 @@
1
  var humanMsg={setup:function(a,b){humanMsg.msgID="humanMsg";humanMsg.logID="humanMsgLog";if(a==undefined)a="body";humanMsg.msgOpacity=0.8;if(b!=undefined)humanMsg.msgOpacity=parseFloat(b);jQuery(a).append('<div id="'+humanMsg.msgID+'" class="humanMsg"><div class="round"></div><p></p><div class="round"></div></div>');jQuery("#"+humanMsg.logID+" p").click(function(){jQuery(this).siblings("ul").slideToggle()})},displayMsg:function(a){if(a!=""){clearTimeout(humanMsg.t2);jQuery("#"+humanMsg.msgID+" p").html(a);
2
  jQuery("#"+humanMsg.msgID+"").show().animate({opacity:humanMsg.msgOpacity},200,function(){jQuery("#"+humanMsg.logID).show().children("ul").prepend("<li>"+a+"</li>").children("li:first").slideDown(200);jQuery("#"+humanMsg.logID+" ul").css("display")=="none"&&jQuery("#"+humanMsg.logID+" p").animate({bottom:40},200,"linear",function(){jQuery(this).animate({bottom:0},300,"easeOutBounce",function(){jQuery(this).css({bottom:0})})})});humanMsg.t1=setTimeout("humanMsg.bindEvents()",700);humanMsg.t2=setTimeout("humanMsg.removeMsg()",
3
- 5000)}},bindEvents:function(){jQuery(window).mousemove(humanMsg.removeMsg).click(humanMsg.removeMsg).keypress(humanMsg.removeMsg)},removeMsg:function(){jQuery(window).unbind("mousemove",humanMsg.removeMsg).unbind("click",humanMsg.removeMsg).unbind("keypress",humanMsg.removeMsg);jQuery("#"+humanMsg.msgID).css("opacity")==humanMsg.msgOpacity&&jQuery("#"+humanMsg.msgID).animate({opacity:0},500,function(){jQuery(this).hide()})}};jQuery(document).ready(function(){humanMsg.setup()});jQuery.cookie=function(a,b,d){if(typeof b!="undefined"){d=d||{};if(b===null){b="";d.expires=-1}var c="";if(d.expires&&(typeof d.expires=="number"||d.expires.toUTCString)){if(typeof d.expires=="number"){c=new Date;c.setTime(c.getTime()+d.expires*24*60*60*1000)}else c=d.expires;c="; expires="+c.toUTCString()}var e=d.path?"; path="+d.path:"",f=d.domain?"; domain="+d.domain:"";d=d.secure?"; secure":"";document.cookie=[a,"=",encodeURIComponent(b),c,e,f,d].join("")}else{b=null;if(document.cookie&&document.cookie!=
 
 
 
 
4
  ""){d=document.cookie.split(";");for(c=0;c<d.length;c++){e=jQuery.trim(d[c]);if(e.substring(0,a.length+1)==a+"="){b=decodeURIComponent(e.substring(a.length+1));break}}}return b}};(function(a){a.fn.bgIframe=a.fn.bgiframe=function(b){if(a.browser.msie&&parseInt(a.browser.version)<=6){b=a.extend({top:"auto",left:"auto",width:"auto",height:"auto",opacity:true,src:"javascript:false;"},b||{});var d=function(e){return e&&e.constructor==Number?e+"px":e},c='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+b.src+'"style="display:block;position:absolute;z-index:-1;'+(b.opacity!==false?"filter:Alpha(Opacity='0');":"")+"top:"+(b.top=="auto"?"expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+'px')":
5
- d(b.top))+";left:"+(b.left=="auto"?"expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+'px')":d(b.left))+";width:"+(b.width=="auto"?"expression(this.parentNode.offsetWidth+'px')":d(b.width))+";height:"+(b.height=="auto"?"expression(this.parentNode.offsetHeight+'px')":d(b.height))+';"/>';return this.each(function(){a("> iframe.bgiframe",this).length==0&&this.insertBefore(document.createElement(c),this.firstChild)})}return this};if(!a.browser.version)a.browser.version=navigator.userAgent.toLowerCase().match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)[1]})(jQuery);(function(a){a.each({focus:"focusin",blur:"focusout"},function(b,d){a.event.special[d]={setup:function(){if(a.browser.msie)return false;this.addEventListener(b,a.event.special[d].handler,true)},teardown:function(){if(a.browser.msie)return false;this.removeEventListener(b,a.event.special[d].handler,true)},handler:function(c){arguments[0]=a.event.fix(c);arguments[0].type=d;return a.event.handle.apply(this,arguments)}}});a.extend(a.fn,{delegate:function(b,d,c){return this.bind(b,function(e){var f=a(e.target);
6
- if(f.is(d))return c.apply(f,arguments)})},triggerEvent:function(b,d){return this.triggerHandler(b,[a.event.fix({type:b,target:d})])}})})(jQuery);(function(a){a.tools=a.tools||{};a.tools.scrollable={version:"1.1.2",conf:{size:5,vertical:false,speed:400,keyboard:true,keyboardSteps:null,disabledClass:"disabled",hoverClass:null,clickable:true,activeClass:"active",easing:"swing",loop:false,items:".items",item:null,prev:".prev",next:".next",prevPage:".prevPage",nextPage:".nextPage",api:false}};var b;function d(c,e){var f=this,m=a(this),n=!e.vertical,k=c.children(),g=0,i;b||(b=f);a.each(e,function(h,j){a.isFunction(j)&&m.bind(h,j)});if(k.length>
7
- 1)k=a(e.items,c);function l(h){var j=a(h);return e.globalNav?j:c.parent().find(h)}c.data("finder",l);var o=l(e.prev),r=l(e.next),q=l(e.prevPage),p=l(e.nextPage);a.extend(f,{getIndex:function(){return g},getClickIndex:function(){var h=f.getItems();return h.index(h.filter("."+e.activeClass))},getConf:function(){return e},getSize:function(){return f.getItems().size()},getPageAmount:function(){return Math.ceil(this.getSize()/e.size)},getPageIndex:function(){return Math.ceil(g/e.size)},getNaviButtons:function(){return o.add(r).add(q).add(p)},
8
- getRoot:function(){return c},getItemWrap:function(){return k},getItems:function(){return k.children(e.item)},getVisibleItems:function(){return f.getItems().slice(g,g+e.size)},seekTo:function(h,j,s){if(h<0)h=0;if(g===h)return f;if(a.isFunction(j))s=j;if(h>f.getSize()-e.size)return e.loop?f.begin():this.end();var u=f.getItems().eq(h);if(!u.length)return f;var w=a.Event("onBeforeSeek");m.trigger(w,[h]);if(w.isDefaultPrevented())return f;if(j===undefined||a.isFunction(j))j=e.speed;function x(){s&&s.call(f,
9
- h);m.trigger("onSeek",[h])}n?k.animate({left:-u.position().left},j,e.easing,x):k.animate({top:-u.position().top},j,e.easing,x);b=f;g=h;w=a.Event("onStart");m.trigger(w,[h]);if(w.isDefaultPrevented())return f;o.add(q).toggleClass(e.disabledClass,h===0);r.add(p).toggleClass(e.disabledClass,h>=f.getSize()-e.size);return f},move:function(h,j,s){i=h>0;return this.seekTo(g+h,j,s)},next:function(h,j){return this.move(1,h,j)},prev:function(h,j){return this.move(-1,h,j)},movePage:function(h,j,s){i=h>0;var u=
10
- e.size*h,w=g%e.size;if(w>0)u+=h>0?-w:e.size-w;return this.move(u,j,s)},prevPage:function(h,j){return this.movePage(-1,h,j)},nextPage:function(h,j){return this.movePage(1,h,j)},setPage:function(h,j,s){return this.seekTo(h*e.size,j,s)},begin:function(h,j){i=false;return this.seekTo(0,h,j)},end:function(h,j){i=true;var s=this.getSize()-e.size;return s>0?this.seekTo(s,h,j):f},reload:function(){m.trigger("onReload");return f},focus:function(){return b=f},click:function(h){var j=f.getItems().eq(h),s=e.activeClass,
11
- u=e.size;if(h<0||h>=f.getSize())return f;if(u==1){if(e.loop)return f.next();if(h===0||h==f.getSize()-1)i=i===undefined?true:!i;return i===false?f.prev():f.next()}if(u==2){h==g&&h--;f.getItems().removeClass(s);j.addClass(s);return f.seekTo(h,time,fn)}if(!j.hasClass(s)){f.getItems().removeClass(s);j.addClass(s);j=Math.floor(u/2);j=h-j;if(j>f.getSize()-u)j=f.getSize()-u;if(j!==h)return f.seekTo(j)}return f},bind:function(h,j){m.bind(h,j);return f},unbind:function(h){m.unbind(h);return f}});a.each("onBeforeSeek,onStart,onSeek,onReload".split(","),
12
- function(h,j){f[j]=function(s){return f.bind(j,s)}});o.addClass(e.disabledClass).click(function(){f.prev()});r.click(function(){f.next()});p.click(function(){f.nextPage()});f.getSize()<e.size&&r.add(p).addClass(e.disabledClass);q.addClass(e.disabledClass).click(function(){f.prevPage()});var t=e.hoverClass,v="keydown."+Math.random().toString().substring(10);f.onReload(function(){t&&f.getItems().hover(function(){a(this).addClass(t)},function(){a(this).removeClass(t)});e.clickable&&f.getItems().each(function(h){a(this).unbind("click.scrollable").bind("click.scrollable",
13
- function(j){if(!a(j.target).is("a"))return f.click(h)})});e.keyboard?a(document).unbind(v).bind(v,function(h){if(!(h.altKey||h.ctrlKey))if(!(e.keyboard!="static"&&b!=f)){var j=e.keyboardSteps;if(n&&(h.keyCode==37||h.keyCode==39)){f.move(h.keyCode==37?-j:j);return h.preventDefault()}if(!n&&(h.keyCode==38||h.keyCode==40)){f.move(h.keyCode==38?-j:j);return h.preventDefault()}return true}}):a(document).unbind(v)});f.reload()}a.fn.scrollable=function(c){var e=this.eq(typeof c=="number"?c:0).data("scrollable");
14
- if(e)return e;var f=a.extend({},a.tools.scrollable.conf);c=a.extend(f,c);c.keyboardSteps=c.keyboardSteps||c.size;this.each(function(){e=new d(a(this),c);a(this).data("scrollable",e)});return c.api?e:this}})(jQuery);
15
- (function(a){var b=a.tools.scrollable;b.plugins=b.plugins||{};b.plugins.autoscroll={version:"1.0.1",conf:{autoplay:true,interval:3000,autopause:true,steps:1,api:false}};a.fn.autoscroll=function(d){if(typeof d=="number")d={interval:d};var c=a.extend({},b.plugins.autoscroll.conf),e;a.extend(c,d);this.each(function(){var f=a(this).scrollable();if(f)e=f;var m,n,k=true;f.play=function(){if(!m){k=false;m=setInterval(function(){f.move(c.steps)},c.interval);f.move(c.steps)}};f.pause=function(){m=clearInterval(m)};
16
- f.stop=function(){f.pause();k=true};c.autopause&&f.getRoot().add(f.getNaviButtons()).hover(function(){f.pause();clearInterval(n)},function(){k||(n=setTimeout(f.play,c.interval))});c.autoplay&&setTimeout(f.play,c.interval)});return c.api?e:this}})(jQuery);
17
- (function(a){var b=a.tools.scrollable;b.plugins=b.plugins||{};b.plugins.navigator={version:"1.0.2",conf:{navi:".navi",naviItem:null,activeClass:"active",indexed:false,api:false,idPrefix:null}};a.fn.navigator=function(d){var c=a.extend({},b.plugins.navigator.conf),e;if(typeof d=="string")d={navi:d};d=a.extend(c,d);this.each(function(){var f=a(this).scrollable(),m=f.getRoot(),n=m.data("finder").call(null,d.navi),k=null,g=f.getNaviButtons();if(f)e=f;f.getNaviButtons=function(){return g.add(n)};function i(){if(!n.children().length||
18
- n.data("navi")==f){n.empty();n.data("navi",f);for(var l=0;l<f.getPageAmount();l++)n.append(a("<"+(d.naviItem||"a")+"/>"));k=n.children().each(function(o){var r=a(this);r.click(function(q){f.setPage(o);return q.preventDefault()});d.indexed&&r.text(o);d.idPrefix&&r.attr("id",d.idPrefix+o)})}else{k=d.naviItem?n.find(d.naviItem):n.children();k.each(function(o){var r=a(this);r.click(function(q){f.setPage(o);return q.preventDefault()})})}k.eq(0).addClass(d.activeClass)}f.onStart(function(){var l=d.activeClass;
19
- k.removeClass(l).eq(f.getPageIndex()).addClass(l)});f.onReload(function(){i()});i();m=k.filter("[href="+location.hash+"]");m.length&&f.move(k.index(m))});return d.api?e:this}})(jQuery);
20
  (function(a){a.fn.wheel=function(e){return this[e?"bind":"trigger"]("wheel",e)};a.event.special.wheel={setup:function(){a.event.add(this,b,d,{})},teardown:function(){a.event.remove(this,b,d)}};var b=!a.browser.mozilla?"mousewheel":"DOMMouseScroll"+(a.browser.version<"1.9"?" mousemove":"");function d(e){switch(e.type){case "mousemove":return a.extend(e.data,{clientX:e.clientX,clientY:e.clientY,pageX:e.pageX,pageY:e.pageY});case "DOMMouseScroll":a.extend(e,e.data);e.delta=-e.detail/3;break;case "mousewheel":e.delta=
21
- e.wheelDelta/120;break}e.type="wheel";return a.event.handle.call(this,e,e.delta)}var c=a.tools.scrollable;c.plugins=c.plugins||{};c.plugins.mousewheel={version:"1.0.1",conf:{api:false,speed:50}};a.fn.mousewheel=function(e){var f=a.extend({},c.plugins.mousewheel.conf),m;if(typeof e=="number")e={speed:e};e=a.extend(f,e);this.each(function(){var n=a(this).scrollable();if(n)m=n;n.getRoot().wheel(function(k,g){n.move(g<0?1:-1,e.speed||50);return false})});return e.api?m:this}})(jQuery);(function(a){a.fn.timePicker=function(k){var g=a.extend({},a.fn.timePicker.defaults,k);return this.each(function(){a.timePicker(this,g)})};a.timePicker=function(k,g){k=a(k)[0];return k.timePicker||(k.timePicker=new jQuery._timePicker(k,g))};a._timePicker=function(k,g){var i=false,l=false,o=f(g.startTime,g),r=f(g.endTime,g);a(k).attr("autocomplete","OFF");for(var q=[],p=new Date(o);p<=r;){q[q.length]=d(p,g);p=new Date(p.setMinutes(p.getMinutes()+g.step))}var t=a("<div "+(g.tpDivId?'id="'+g.tpDivId+
22
- '" ':"")+'class="time-picker'+(g.show24Hours?"":" time-picker-12hours")+'"></div>'),v=a("<ul></ul>");for(p=0;p<q.length;p++)v.append("<li>"+q[p]+"</li>");t.append(v);q=a(k).offset();t.appendTo("body").css({top:q.top-48+"px",left:q.left,width:a(k).width()+5+"px"}).hide();t.mouseover(function(){i=true}).mouseout(function(){i=false});a("li",v).mouseover(function(){if(!l){a("li.selected",t).removeClass("selected");a(this).addClass("selected")}}).mousedown(function(){i=true}).click(function(){b(k,this,
23
- t,g);i=false});function h(){if(t.is(":visible"))return false;a("li",t).removeClass("selected");var j=a(k).offset();t.css({top:j.top-48+"px",left:j.left,width:a(k).width()+5+"px"});t.show();var s=k.value?m(k.value,g):o;j=o.getHours()*60+o.getMinutes();s=s.getHours()*60+s.getMinutes()-j;s=Math.round(s/g.step);j=n(new Date(0,0,0,0,s*g.step+j,0));j=o<j&&j<=r?j:o;j=a("li:contains("+d(j,g)+")",t);if(j.length){j.addClass("selected");t[0].scrollTop=j[0].offsetTop}return true}a(k).focus(h).click(h);a(k).blur(function(){i||
24
- t.hide()});q=a.browser.opera||a.browser.mozilla?"keypress":"keydown";a(k)[q](function(j){l=true;var s=t[0].scrollTop;switch(j.keyCode){case 38:if(h())return false;j=a("li.selected",v);var u=j.prev().addClass("selected")[0];if(u){j.removeClass("selected");if(u.offsetTop<s)t[0].scrollTop=s-u.offsetHeight}else{j.removeClass("selected");u=a("li:last",v).addClass("selected")[0];t[0].scrollTop=u.offsetTop-u.offsetHeight}return false;case 40:if(h())return false;j=a("li.selected",v);if(u=j.next().addClass("selected")[0]){j.removeClass("selected");
25
- if(u.offsetTop+u.offsetHeight>s+t[0].offsetHeight)t[0].scrollTop=s+u.offsetHeight}else{j.removeClass("selected");a("li:first",v).addClass("selected");t[0].scrollTop=0}return false;case 13:if(t.is(":visible")){s=a("li.selected",v)[0];b(k,s,t,g)}return false;case 27:t.hide();return false}return true});a(k).keyup(function(){l=false});this.getTime=function(){return m(k.value,g)};this.setTime=function(j){k.value=d(n(j),g);a(k).change()}};a.fn.timePicker.defaults={step:30,startTime:new Date(0,0,0,0,0,0),
26
- endTime:new Date(0,0,0,23,30,0),separator:":",show24Hours:true};function b(k,g,i){k.value=a(g).text();a(k).change();a.browser.msie||k.focus();i.hide()}function d(k,g){var i=k.getHours(),l=g.show24Hours?i:(i+11)%12+1;l=e(l,g);k=k.getMinutes();return l+g.separator+c(k)+(g.show24Hours?"":i<12?" AM":" PM")}function c(k){return(k<10?"0":"")+k}function e(k,g){return g.show24Hours?(k<10?"0":"")+k:k}function f(k,g){return typeof k=="object"?n(k):m(k,g)}function m(k,g){if(k){var i=k.split(g.separator),l=parseFloat(i[0]);
27
- i=parseFloat(i[1]);if(!g.show24Hours)if(l===12&&k.substr("AM")!==-1)l=0;else if(l!==12&&k.indexOf("PM")!==-1)l+=12;k=new Date(0,0,0,l,i,0);return n(k)}return null}function n(k){k.setFullYear(2001);k.setMonth(0);k.setDate(0);return k}})(jQuery);if(!this.JSON)this.JSON={};
28
- (function(){function a(g){return g<10?"0"+g:g}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+a(this.getUTCMonth()+1)+"-"+a(this.getUTCDate())+"T"+a(this.getUTCHours())+":"+a(this.getUTCMinutes())+":"+a(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()}}var b=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,d=
29
- /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,c,e,f={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},m;function n(g){d.lastIndex=0;return d.test(g)?'"'+g.replace(d,function(i){var l=f[i];return typeof l==="string"?l:"\\u"+("0000"+i.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+g+'"'}function k(g,i){var l,o,r=c,q,p=i[g];if(p&&typeof p==="object"&&typeof p.toJSON==="function")p=p.toJSON(g);
30
- if(typeof m==="function")p=m.call(i,g,p);switch(typeof p){case "string":return n(p);case "number":return isFinite(p)?String(p):"null";case "boolean":case "null":return String(p);case "object":if(!p)return"null";c+=e;q=[];if(Object.prototype.toString.apply(p)==="[object Array]"){o=p.length;for(g=0;g<o;g+=1)q[g]=k(g,p)||"null";i=q.length===0?"[]":c?"[\n"+c+q.join(",\n"+c)+"\n"+r+"]":"["+q.join(",")+"]";c=r;return i}if(m&&typeof m==="object"){o=m.length;for(g=0;g<o;g+=1){l=m[g];if(typeof l==="string")if(i=
31
- k(l,p))q.push(n(l)+(c?": ":":")+i)}}else for(l in p)if(Object.hasOwnProperty.call(p,l))if(i=k(l,p))q.push(n(l)+(c?": ":":")+i);i=q.length===0?"{}":c?"{\n"+c+q.join(",\n"+c)+"\n"+r+"}":"{"+q.join(",")+"}";c=r;return i}}if(typeof JSON.stringify!=="function")JSON.stringify=function(g,i,l){var o;e=c="";if(typeof l==="number")for(o=0;o<l;o+=1)e+=" ";else if(typeof l==="string")e=l;if((m=i)&&typeof i!=="function"&&(typeof i!=="object"||typeof i.length!=="number"))throw new Error("JSON.stringify");return k("",
32
- {"":g})};if(typeof JSON.parseIt!=="function")JSON.parseIt=function(g,i){function l(o,r){var q,p,t=o[r];if(t&&typeof t==="object")for(q in t)if(Object.hasOwnProperty.call(t,q)){p=l(t,q);if(p!==undefined)t[q]=p;else delete t[q]}return i.call(o,r,t)}b.lastIndex=0;if(b.test(g))g=g.replace(b,function(o){return"\\u"+("0000"+o.charCodeAt(0).toString(16)).slice(-4)});if(/^[\],:{}\s]*$/.test(g.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
33
- "]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){g=eval("("+g+")");return typeof i==="function"?l({"":g},""):g}throw new SyntaxError("JSON.parseIt");}})();(function(a){a.tools=a.tools||{};a.tools.scrollable={version:"1.1.2",conf:{size:5,vertical:false,speed:400,keyboard:true,keyboardSteps:null,disabledClass:"disabled",hoverClass:null,clickable:true,activeClass:"active",easing:"swing",loop:false,items:".items",item:null,prev:".prev",next:".next",prevPage:".prevPage",nextPage:".nextPage",api:false}};var b;function d(c,e){var f=this,m=a(this),n=!e.vertical,k=c.children(),g=0,i;b||(b=f);a.each(e,function(h,j){a.isFunction(j)&&m.bind(h,j)});if(k.length>
34
- 1)k=a(e.items,c);function l(h){var j=a(h);return e.globalNav?j:c.parent().find(h)}c.data("finder",l);var o=l(e.prev),r=l(e.next),q=l(e.prevPage),p=l(e.nextPage);a.extend(f,{getIndex:function(){return g},getClickIndex:function(){var h=f.getItems();return h.index(h.filter("."+e.activeClass))},getConf:function(){return e},getSize:function(){return f.getItems().size()},getPageAmount:function(){return Math.ceil(this.getSize()/e.size)},getPageIndex:function(){return Math.ceil(g/e.size)},getNaviButtons:function(){return o.add(r).add(q).add(p)},
35
- getRoot:function(){return c},getItemWrap:function(){return k},getItems:function(){return k.children(e.item)},getVisibleItems:function(){return f.getItems().slice(g,g+e.size)},seekTo:function(h,j,s){if(h<0)h=0;if(g===h)return f;if(a.isFunction(j))s=j;if(h>f.getSize()-e.size)return e.loop?f.begin():this.end();var u=f.getItems().eq(h);if(!u.length)return f;var w=a.Event("onBeforeSeek");m.trigger(w,h>g);if(w.isDefaultPrevented())return f;if(j===undefined||a.isFunction(j))j=e.speed;function x(){s&&s.call(f,
36
- h);m.trigger("onSeek",[h])}n?k.animate({left:-u.position().left},j,e.easing,x):k.animate({top:-u.position().top},j,e.easing,x);b=f;g=h;w=a.Event("onStart");m.trigger(w,[h]);if(w.isDefaultPrevented())return f;o.add(q).toggleClass(e.disabledClass,h===0);r.add(p).toggleClass(e.disabledClass,h>=f.getSize()-e.size);return f},move:function(h,j,s){i=h>0;return this.seekTo(g+h,j,s)},next:function(h,j){return this.move(1,h,j)},prev:function(h,j){return this.move(-1,h,j)},movePage:function(h,j,s){i=h>0;var u=
37
- e.size*h,w=g%e.size;if(w>0)u+=h>0?-w:e.size-w;return this.move(u,j,s)},prevPage:function(h,j){return this.movePage(-1,h,j)},nextPage:function(h,j){return this.movePage(1,h,j)},setPage:function(h,j,s){return this.seekTo(h*e.size,j,s)},begin:function(h,j){i=false;return this.seekTo(0,h,j)},end:function(h,j){i=true;var s=this.getSize()-e.size;return s>0?this.seekTo(s,h,j):f},reload:function(){m.trigger("onReload");return f},focus:function(){return b=f},click:function(h){var j=f.getItems().eq(h),s=e.activeClass,
38
- u=e.size;if(h<0||h>=f.getSize())return f;if(u==1){if(e.loop)return f.next();if(h===0||h==f.getSize()-1)i=i===undefined?true:!i;return i===false?f.prev():f.next()}if(u==2){h==g&&h--;f.getItems().removeClass(s);j.addClass(s);return f.seekTo(h,time,fn)}if(!j.hasClass(s)){f.getItems().removeClass(s);j.addClass(s);j=Math.floor(u/2);j=h-j;if(j>f.getSize()-u)j=f.getSize()-u;if(j!==h)return f.seekTo(j)}return f},bind:function(h,j){m.bind(h,j);return f},unbind:function(h){m.unbind(h);return f}});a.each("onBeforeSeek,onStart,onSeek,onReload".split(","),
39
- function(h,j){f[j]=function(s){return f.bind(j,s)}});o.addClass(e.disabledClass).click(function(){f.prev()});r.click(function(){f.next()});p.click(function(){f.nextPage()});f.getSize()<e.size&&r.add(p).addClass(e.disabledClass);q.addClass(e.disabledClass).click(function(){f.prevPage()});var t=e.hoverClass,v="keydown."+Math.random().toString().substring(10);f.onReload(function(){t&&f.getItems().hover(function(){a(this).addClass(t)},function(){a(this).removeClass(t)});e.clickable&&f.getItems().each(function(h){a(this).unbind("click.scrollable").bind("click.scrollable",
40
- function(j){if(!a(j.target).is("a"))return f.click(h)})});e.keyboard?a(document).unbind(v).bind(v,function(h){if(!(h.altKey||h.ctrlKey))if(!(e.keyboard!="static"&&b!=f)){var j=e.keyboardSteps;if(n&&(h.keyCode==37||h.keyCode==39)){f.move(h.keyCode==37?-j:j);return h.preventDefault()}if(!n&&(h.keyCode==38||h.keyCode==40)){f.move(h.keyCode==38?-j:j);return h.preventDefault()}return true}}):a(document).unbind(v)});f.reload()}a.fn.scrollable=function(c){var e=this.eq(typeof c=="number"?c:0).data("scrollable");
41
- if(e)return e;var f=a.extend({},a.tools.scrollable.conf);c=a.extend(f,c);c.keyboardSteps=c.keyboardSteps||c.size;this.each(function(){e=new d(a(this),c);a(this).data("scrollable",e)});return c.api?e:this}})(jQuery);(function(a){a.fn.wheel=function(e){return this[e?"bind":"trigger"]("wheel",e)};a.event.special.wheel={setup:function(){a.event.add(this,b,d,{})},teardown:function(){a.event.remove(this,b,d)}};var b=!a.browser.mozilla?"mousewheel":"DOMMouseScroll"+(a.browser.version<"1.9"?" mousemove":"");function d(e){switch(e.type){case "mousemove":return a.extend(e.data,{clientX:e.clientX,clientY:e.clientY,pageX:e.pageX,pageY:e.pageY});case "DOMMouseScroll":a.extend(e,e.data);e.delta=-e.detail/3;break;case "mousewheel":e.delta=
42
- e.wheelDelta/120;break}e.type="wheel";return a.event.handle.call(this,e,e.delta)}var c=a.tools.scrollable;c.plugins=c.plugins||{};c.plugins.mousewheel={version:"1.0.1",conf:{api:false,speed:50}};a.fn.mousewheel=function(e){var f=a.extend({},c.plugins.mousewheel.conf),m;if(typeof e=="number")e={speed:e};e=a.extend(f,e);this.each(function(){var n=a(this).scrollable();if(n)m=n;n.getRoot().wheel(function(k,g){n.move(g<0?1:-1,e.speed||50);return false})});return e.api?m:this}})(jQuery);jQuery.ui||function(a){var b=a.fn.remove,d=a.browser.mozilla&&parseFloat(a.browser.version)<1.9;a.ui={version:"1.7.2",plugin:{add:function(g,i,l){g=a.ui[g].prototype;for(var o in l){g.plugins[o]=g.plugins[o]||[];g.plugins[o].push([i,l[o]])}},call:function(g,i,l){if((i=g.plugins[i])&&g.element[0].parentNode)for(var o=0;o<i.length;o++)g.options[i[o][0]]&&i[o][1].apply(g.element,l)}},contains:function(g,i){return document.compareDocumentPosition?g.compareDocumentPosition(i)&16:g!==i&&g.contains(i)},
43
- hasScroll:function(g,i){if(a(g).css("overflow")=="hidden")return false;i=i&&i=="left"?"scrollLeft":"scrollTop";var l=false;if(g[i]>0)return true;g[i]=1;l=g[i]>0;g[i]=0;return l},isOverAxis:function(g,i,l){return g>i&&g<i+l},isOver:function(g,i,l,o,r,q){return a.ui.isOverAxis(g,l,r)&&a.ui.isOverAxis(i,o,q)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,
44
- NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var c=a.attr,e=a.fn.removeAttr,f="http://www.w3.org/2005/07/aaa",m=/^aria-/,n=/^wairole:/;a.attr=function(g,i,l){var o=l!==undefined;return i=="role"?o?c.call(this,g,i,"wairole:"+l):(c.apply(this,arguments)||"").replace(n,""):m.test(i)?o?g.setAttributeNS(f,i.replace(m,"aaa:"),l):c.call(this,g,i.replace(m,"aaa:")):c.apply(this,arguments)};a.fn.removeAttr=function(g){return m.test(g)?
45
- this.each(function(){this.removeAttributeNS(f,g.replace(m,""))}):e.call(this,g)}}a.fn.extend({remove:function(){a("*",this).add(this).each(function(){a(this).triggerHandler("remove")});return b.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var g;
46
- g=a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||
47
- !g.length?a(document):g}});a.extend(a.expr[":"],{data:function(g,i,l){return!!a.data(g,l[3])},focusable:function(g){var i=g.nodeName.toLowerCase(),l=a.attr(g,"tabindex");return(/input|select|textarea|button|object/.test(i)?!g.disabled:"a"==i||"area"==i?g.href||!isNaN(l):!isNaN(l))&&!a(g)["area"==i?"parents":"closest"](":hidden").length},tabbable:function(g){var i=a.attr(g,"tabindex");return(isNaN(i)||i>=0)&&a(g).is(":focusable")}});function k(g,i,l,o){function r(p){p=a[g][i][p]||[];return typeof p==
48
- "string"?p.split(/,?\s+/):p}var q=r("getter");if(o.length==1&&typeof o[0]=="string")q=q.concat(r("getterSetter"));return a.inArray(l,q)!=-1}a.widget=function(g,i){var l=g.split(".")[0];g=g.split(".")[1];a.fn[g]=function(o){var r=typeof o=="string",q=Array.prototype.slice.call(arguments,1);if(r&&o.substring(0,1)=="_")return this;if(r&&k(l,g,o,q)){var p=a.data(this[0],g);return p?p[o].apply(p,q):undefined}return this.each(function(){var t=a.data(this,g);!t&&!r&&a.data(this,g,new a[l][g](this,o))._init();
49
- t&&r&&a.isFunction(t[o])&&t[o].apply(t,q)})};a[l]=a[l]||{};a[l][g]=function(o,r){var q=this;this.namespace=l;this.widgetName=g;this.widgetEventPrefix=a[l][g].eventPrefix||g;this.widgetBaseClass=l+"-"+g;this.options=a.extend({},a.widget.defaults,a[l][g].defaults,a.metadata&&a.metadata.get(o)[g],r);this.element=a(o).bind("setData."+g,function(p,t,v){if(p.target==o)return q._setData(t,v)}).bind("getData."+g,function(p,t){if(p.target==o)return q._getData(t)}).bind("remove",function(){return q.destroy()})};
50
- a[l][g].prototype=a.extend({},a.widget.prototype,i);a[l][g].getterSetter="option"};a.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(g,i){var l=g,o=this;if(typeof g=="string"){if(i===undefined)return this._getData(g);l={};l[g]=i}a.each(l,function(r,q){o._setData(r,q)})},_getData:function(g){return this.options[g]},_setData:function(g,
51
- i){this.options[g]=i;if(g=="disabled")this.element[i?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",i)},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(g,i,l){var o=this.options[g];g=g==this.widgetEventPrefix?g:this.widgetEventPrefix+g;i=a.Event(i);i.type=g;if(i.originalEvent){g=a.event.props.length;for(var r;g;){r=a.event.props[--g];i[r]=i.originalEvent[r]}}this.element.trigger(i,
52
- l);return!(a.isFunction(o)&&o.call(this.element[0],i,l)===false||i.isDefaultPrevented())}};a.widget.defaults={disabled:false};a.ui.mouse={_mouseInit:function(){var g=this;this.element.bind("mousedown."+this.widgetName,function(i){return g._mouseDown(i)}).bind("click."+this.widgetName,function(i){if(g._preventClickEvent){g._preventClickEvent=false;i.stopImmediatePropagation();return false}});if(a.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable",
53
- "on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);a.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable)},_mouseDown:function(g){g.originalEvent=g.originalEvent||{};if(!g.originalEvent.mouseHandled){this._mouseStarted&&this._mouseUp(g);this._mouseDownEvent=g;var i=this,l=g.which==1,o=typeof this.options.cancel=="string"?a(g.target).parents().add(g.target).filter(this.options.cancel).length:false;if(!l||o||!this._mouseCapture(g))return true;
54
- this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(g)&&this._mouseDelayMet(g)){this._mouseStarted=this._mouseStart(g)!==false;if(!this._mouseStarted){g.preventDefault();return true}}this._mouseMoveDelegate=function(r){return i._mouseMove(r)};this._mouseUpDelegate=function(r){return i._mouseUp(r)};a(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+
55
- this.widgetName,this._mouseUpDelegate);a.browser.safari||g.preventDefault();return g.originalEvent.mouseHandled=true}},_mouseMove:function(g){if(a.browser.msie&&!g.button)return this._mouseUp(g);if(this._mouseStarted){this._mouseDrag(g);return g.preventDefault()}if(this._mouseDistanceMet(g)&&this._mouseDelayMet(g))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,g)!==false)?this._mouseDrag(g):this._mouseUp(g);return!this._mouseStarted},_mouseUp:function(g){a(document).unbind("mousemove."+
56
- this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=g.target==this._mouseDownEvent.target;this._mouseStop(g)}return false},_mouseDistanceMet:function(g){return Math.max(Math.abs(this._mouseDownEvent.pageX-g.pageX),Math.abs(this._mouseDownEvent.pageY-g.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},
57
  _mouseStop:function(){},_mouseCapture:function(){return true}};a.ui.mouse.defaults={cancel:null,distance:1,delay:0}}(jQuery);(function(a){a.widget("ui.draggable",a.extend({},a.ui.mouse,{_init:function(){if(this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");
58
  this._mouseDestroy()}},_mouseCapture:function(b){var d=this.options;if(this.helper||d.disabled||a(b.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(b);if(!this.handle)return false;return true},_mouseStart:function(b){var d=this.options;this.helper=this._createHelper(b);this._cacheHelperProportions();if(a.ui.ddmanager)a.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.element.offset();
59
  this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(b);this.originalPageX=b.pageX;this.originalPageY=b.pageY;d.cursorAt&&this._adjustOffsetFromHelper(d.cursorAt);d.containment&&this._setContainment();this._trigger("start",b);this._cacheHelperProportions();a.ui.ddmanager&&
@@ -68,12 +72,12 @@ this.margins.left,(a(b.containment=="document"?document:window).height()||docume
68
  10)||0)+(parseInt(a(d).css("paddingTop"),10)||0)-this.margins.top,b.left+(c?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,b.top+(c?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}}else if(b.containment.constructor==
69
  Array)this.containment=b.containment},_convertPositionTo:function(b,d){if(!d)d=this.position;b=b=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:d.top+this.offset.relative.top*b+this.offset.parent.top*b-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*
70
  b),left:d.left+this.offset.relative.left*b+this.offset.parent.left*b-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())*b)}},_generatePosition:function(b){var d=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=
71
- document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset();var f=b.pageX,m=b.pageY;if(this.originalPosition){if(this.containment){if(b.pageX-this.offset.click.left<this.containment[0])f=this.containment[0]+this.offset.click.left;if(b.pageY-this.offset.click.top<this.containment[1])m=this.containment[1]+this.offset.click.top;if(b.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(b.pageY-this.offset.click.top>this.containment[3])m=
72
- this.containment[3]+this.offset.click.top}if(d.grid){m=this.originalPageY+Math.round((m-this.originalPageY)/d.grid[1])*d.grid[1];m=this.containment?!(m-this.offset.click.top<this.containment[1]||m-this.offset.click.top>this.containment[3])?m:!(m-this.offset.click.top<this.containment[1])?m-d.grid[1]:m+d.grid[1]:m;f=this.originalPageX+Math.round((f-this.originalPageX)/d.grid[0])*d.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?
73
- f:!(f-this.offset.click.left<this.containment[0])?f-d.grid[0]:f+d.grid[0]:f}}return{top:m-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");
74
  this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(b,d,c){c=c||this._uiHash();a.ui.plugin.call(this,b,[d,c]);if(b=="drag")this.positionAbs=this._convertPositionTo("absolute");return a.widget.prototype._trigger.call(this,b,d,c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,absolutePosition:this.positionAbs,offset:this.positionAbs}}}));a.extend(a.ui.draggable,{version:"1.7.2",
75
  eventPrefix:"drag",defaults:{addClasses:true,appendTo:"parent",axis:false,cancel:":input,option",connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,delay:0,distance:1,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false}});a.ui.plugin.add("draggable","connectToSortable",{start:function(b,
76
- d){var c=a(this).data("draggable"),e=c.options,f=a.extend({},d,{item:c.element});c.sortables=[];a(e.connectToSortable).each(function(){var m=a.data(this,"sortable");if(m&&!m.options.disabled){c.sortables.push({instance:m,shouldRevert:m.options.revert});m._refreshItems();m._trigger("activate",b,f)}})},stop:function(b,d){var c=a(this).data("draggable"),e=a.extend({},d,{item:c.element});a.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=
77
  false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(b);this.instance.options.helper=this.instance.options._helper;c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",b,e)}})},drag:function(b,d){var c=a(this).data("draggable"),e=this;a.each(c.sortables,function(){this.instance.positionAbs=c.positionAbs;this.instance.helperProportions=c.helperProportions;
78
  this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=a(e).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return d.helper[0]};b.target=this.instance.currentItem[0];this.instance._mouseCapture(b,true);this.instance._mouseStart(b,true,true);this.instance.offset.click.top=
79
  c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;c._trigger("toSortable",b);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(b)}else if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;
@@ -83,27 +87,27 @@ stop:function(){a("div.ui-draggable-iframeFix").each(function(){this.parentNode.
83
  document&&b.scrollParent[0].tagName!="HTML")b.overflowOffset=b.scrollParent.offset()},drag:function(b){var d=a(this).data("draggable"),c=d.options,e=false;if(d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!="x")if(d.overflowOffset.top+d.scrollParent[0].offsetHeight-b.pageY<c.scrollSensitivity)d.scrollParent[0].scrollTop=e=d.scrollParent[0].scrollTop+c.scrollSpeed;else if(b.pageY-d.overflowOffset.top<c.scrollSensitivity)d.scrollParent[0].scrollTop=e=d.scrollParent[0].scrollTop-
84
  c.scrollSpeed;if(!c.axis||c.axis!="y")if(d.overflowOffset.left+d.scrollParent[0].offsetWidth-b.pageX<c.scrollSensitivity)d.scrollParent[0].scrollLeft=e=d.scrollParent[0].scrollLeft+c.scrollSpeed;else if(b.pageX-d.overflowOffset.left<c.scrollSensitivity)d.scrollParent[0].scrollLeft=e=d.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(b.pageY-a(document).scrollTop()<c.scrollSensitivity)e=a(document).scrollTop(a(document).scrollTop()-c.scrollSpeed);else if(a(window).height()-
85
  (b.pageY-a(document).scrollTop())<c.scrollSensitivity)e=a(document).scrollTop(a(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(b.pageX-a(document).scrollLeft()<c.scrollSensitivity)e=a(document).scrollLeft(a(document).scrollLeft()-c.scrollSpeed);else if(a(window).width()-(b.pageX-a(document).scrollLeft())<c.scrollSensitivity)e=a(document).scrollLeft(a(document).scrollLeft()+c.scrollSpeed)}e!==false&&a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(d,b)}});a.ui.plugin.add("draggable",
86
- "snap",{start:function(){var b=a(this).data("draggable"),d=b.options;b.snapElements=[];a(d.snap.constructor!=String?d.snap.items||":data(draggable)":d.snap).each(function(){var c=a(this),e=c.offset();this!=b.element[0]&&b.snapElements.push({item:this,width:c.outerWidth(),height:c.outerHeight(),top:e.top,left:e.left})})},drag:function(b,d){for(var c=a(this).data("draggable"),e=c.options,f=e.snapTolerance,m=d.offset.left,n=m+c.helperProportions.width,k=d.offset.top,g=k+c.helperProportions.height,i=
87
- c.snapElements.length-1;i>=0;i--){var l=c.snapElements[i].left,o=l+c.snapElements[i].width,r=c.snapElements[i].top,q=r+c.snapElements[i].height;if(l-f<m&&m<o+f&&r-f<k&&k<q+f||l-f<m&&m<o+f&&r-f<g&&g<q+f||l-f<n&&n<o+f&&r-f<k&&k<q+f||l-f<n&&n<o+f&&r-f<g&&g<q+f){if(e.snapMode!="inner"){var p=Math.abs(r-g)<=f,t=Math.abs(q-k)<=f,v=Math.abs(l-n)<=f,h=Math.abs(o-m)<=f;if(p)d.position.top=c._convertPositionTo("relative",{top:r-c.helperProportions.height,left:0}).top-c.margins.top;if(t)d.position.top=c._convertPositionTo("relative",
88
- {top:q,left:0}).top-c.margins.top;if(v)d.position.left=c._convertPositionTo("relative",{top:0,left:l-c.helperProportions.width}).left-c.margins.left;if(h)d.position.left=c._convertPositionTo("relative",{top:0,left:o}).left-c.margins.left}var j=p||t||v||h;if(e.snapMode!="outer"){p=Math.abs(r-k)<=f;t=Math.abs(q-g)<=f;v=Math.abs(l-m)<=f;h=Math.abs(o-n)<=f;if(p)d.position.top=c._convertPositionTo("relative",{top:r,left:0}).top-c.margins.top;if(t)d.position.top=c._convertPositionTo("relative",{top:q-c.helperProportions.height,
89
- left:0}).top-c.margins.top;if(v)d.position.left=c._convertPositionTo("relative",{top:0,left:l}).left-c.margins.left;if(h)d.position.left=c._convertPositionTo("relative",{top:0,left:o-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[i].snapping&&(p||t||v||h||j))c.options.snap.snap&&c.options.snap.snap.call(c.element,b,a.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=p||t||v||h||j}else{c.snapElements[i].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,
90
- b,a.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=false}}}});a.ui.plugin.add("draggable","stack",{start:function(){var b=a(this).data("draggable").options,d=a.makeArray(a(b.stack.group)).sort(function(c,e){return(parseInt(a(c).css("zIndex"),10)||b.stack.min)-(parseInt(a(e).css("zIndex"),10)||b.stack.min)});a(d).each(function(c){this.style.zIndex=b.stack.min+c});this[0].style.zIndex=b.stack.min+d.length}});a.ui.plugin.add("draggable","zIndex",{start:function(b,d){b=
91
  a(d.helper);d=a(this).data("draggable").options;if(b.css("zIndex"))d._zIndex=b.css("zIndex");b.css("zIndex",d.zIndex)},stop:function(b,d){b=a(this).data("draggable").options;b._zIndex&&a(d.helper).css("zIndex",b._zIndex)}})})(jQuery);(function(a){a.widget("ui.droppable",{_init:function(){var b=this.options,d=b.accept;this.isover=0;this.isout=1;this.options.accept=this.options.accept&&a.isFunction(this.options.accept)?this.options.accept:function(c){return c.is(d)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};a.ui.ddmanager.droppables[this.options.scope]=a.ui.ddmanager.droppables[this.options.scope]||[];a.ui.ddmanager.droppables[this.options.scope].push(this);this.options.addClasses&&
92
  this.element.addClass("ui-droppable")},destroy:function(){for(var b=a.ui.ddmanager.droppables[this.options.scope],d=0;d<b.length;d++)b[d]==this&&b.splice(d,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable")},_setData:function(b,d){if(b=="accept")this.options.accept=d&&a.isFunction(d)?d:function(c){return c.is(d)};else a.widget.prototype._setData.apply(this,arguments)},_activate:function(b){var d=a.ui.ddmanager.current;this.options.activeClass&&
93
  this.element.addClass(this.options.activeClass);d&&this._trigger("activate",b,this.ui(d))},_deactivate:function(b){var d=a.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);d&&this._trigger("deactivate",b,this.ui(d))},_over:function(b){var d=a.ui.ddmanager.current;if(!(!d||(d.currentItem||d.element)[0]==this.element[0]))if(this.options.accept.call(this.element[0],d.currentItem||d.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass);
94
- this._trigger("over",b,this.ui(d))}},_out:function(b){var d=a.ui.ddmanager.current;if(!(!d||(d.currentItem||d.element)[0]==this.element[0]))if(this.options.accept.call(this.element[0],d.currentItem||d.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",b,this.ui(d))}},_drop:function(b,d){var c=d||a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var f=
95
- a.data(this,"droppable");if(f.options.greedy&&a.ui.intersect(c,a.extend(f,{offset:f.element.offset()}),f.options.tolerance)){e=true;return false}});if(e)return false;if(this.options.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop",b,this.ui(c));return this.element}return false},ui:function(b){return{draggable:b.currentItem||
96
- b.element,helper:b.helper,position:b.position,absolutePosition:b.positionAbs,offset:b.positionAbs}}});a.extend(a.ui.droppable,{version:"1.7.2",eventPrefix:"drop",defaults:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"}});a.ui.intersect=function(b,d,c){if(!d.offset)return false;var e=(b.positionAbs||b.position.absolute).left,f=e+b.helperProportions.width,m=(b.positionAbs||b.position.absolute).top,n=m+b.helperProportions.height,k=d.offset.left,
97
- g=k+d.proportions.width,i=d.offset.top,l=i+d.proportions.height;switch(c){case "fit":return k<e&&f<g&&i<m&&n<l;case "intersect":return k<e+b.helperProportions.width/2&&f-b.helperProportions.width/2<g&&i<m+b.helperProportions.height/2&&n-b.helperProportions.height/2<l;case "pointer":c=(b.positionAbs||b.position.absolute).left+(b.clickOffset||b.offset.click).left;b=(b.positionAbs||b.position.absolute).top+(b.clickOffset||b.offset.click).top;return d=a.ui.isOver(b,c,i,k,d.proportions.height,d.proportions.width);
98
- case "touch":return(m>=i&&m<=l||n>=i&&n<=l||m<i&&n>l)&&(e>=k&&e<=g||f>=k&&f<=g||e<k&&f>g);default:return false}};a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,d){var c=a.ui.ddmanager.droppables[b.options.scope],e=d?d.type:null,f=(b.currentItem||b.element).find(":data(droppable)").andSelf(),m=0;a:for(;m<c.length;m++)if(!(c[m].options.disabled||b&&!c[m].options.accept.call(c[m].element[0],b.currentItem||b.element))){for(var n=0;n<f.length;n++)if(f[n]==c[m].element[0]){c[m].proportions.height=
99
- 0;continue a}c[m].visible=c[m].element.css("display")!="none";if(c[m].visible){c[m].offset=c[m].element.offset();c[m].proportions={width:c[m].element[0].offsetWidth,height:c[m].element[0].offsetHeight};e=="mousedown"&&c[m]._activate.call(c[m],d)}}},drop:function(b,d){var c=false;a.each(a.ui.ddmanager.droppables[b.options.scope],function(){if(this.options){if(!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance))c=this._drop.call(this,d);if(!this.options.disabled&&this.visible&&
100
- this.options.accept.call(this.element[0],b.currentItem||b.element)){this.isout=1;this.isover=0;this._deactivate.call(this,d)}}});return c},drag:function(b,d){b.options.refreshPositions&&a.ui.ddmanager.prepareOffsets(b,d);a.each(a.ui.ddmanager.droppables[b.options.scope],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=a.ui.intersect(b,this,this.options.tolerance);if(c=!c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var f=this.element.parents(":data(droppable):eq(0)");
101
- if(f.length){e=a.data(f[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,d)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,d);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,d)}}}})}}})(jQuery);/*
102
  : Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
103
  */
104
- (function(){var a=Date,b=a.prototype,d=[];function c(e,f){f||(f=2);return("000"+e).slice(f*-1)}a.normalizeFormat=function(e){d=[];(new Date).$format(e);return d.join("")};a.strftime=function(e,f){return(new Date(f*1000)).$format(e)};a.strtotime=function(e){e=a.parse(e);e.addMinutes(e.getTimezoneOffset()*-1);return Math.round(a.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds(),e.getUTCMilliseconds())/1000)};b.$format=function(e){var f=this,m;
105
- function n(k){d.push(k);return f.toString(k)}return e?e.replace(/(%|\\)?.|%%/g,function(k){if(k.charAt(0)==="\\"||k.substring(0,2)==="%%")return k.replace("\\","").replace("%%","%");switch(k){case "d":case "%d":return n("dd");case "D":case "%a":return n("ddd");case "j":case "%e":return n("d");case "l":case "%A":return n("dddd");case "N":case "%u":return f.getDay()+1;case "S":return n("S");case "w":case "%w":return f.getDay();case "z":return f.getOrdinalNumber();case "%j":return c(f.getOrdinalNumber(),
106
- 3);case "%U":k=f.clone().set({month:0,day:1}).addDays(-1).moveToDayOfWeek(0);var g=f.clone().addDays(1).moveToDayOfWeek(0,-1);return g<k?"00":c((g.getOrdinalNumber()-k.getOrdinalNumber())/7+1);case "W":case "%V":return f.getISOWeek();case "%W":return c(f.getWeek());case "F":case "%B":return n("MMMM");case "m":case "%m":return n("MM");case "M":case "%b":case "%h":return n("MMM");case "n":return n("M");case "t":return a.getDaysInMonth(f.getFullYear(),f.getMonth());case "L":return a.isLeapYear(f.getFullYear())?
107
- 1:0;case "o":case "%G":return f.setWeek(f.getISOWeek()).toString("yyyy");case "%g":return f.$format("%G").slice(-2);case "Y":case "%Y":return n("yyyy");case "y":case "%y":return n("yy");case "a":case "%p":return n("tt").toLowerCase();case "A":return n("tt").toUpperCase();case "g":case "%I":return n("h");case "G":return n("H");case "h":return n("hh");case "H":case "%H":return n("HH");case "i":case "%M":return n("mm");case "s":case "%S":return n("ss");case "u":return c(f.getMilliseconds(),3);case "I":return f.isDaylightSavingTime()?
108
- 1:0;case "O":return f.getUTCOffset();case "P":m=f.getUTCOffset();return m.substring(0,m.length-2)+":"+m.substring(m.length-2);case "e":case "T":case "%z":case "%Z":return f.getTimezone();case "Z":return f.getTimezoneOffset()*-60;case "B":k=new Date;return Math.floor((k.getHours()*3600+k.getMinutes()*60+k.getSeconds()+(k.getTimezoneOffset()+60)*60)/86.4);case "c":return f.toISOString().replace(/\"/g,"");case "U":return a.strtotime("now");case "%c":return n("d")+" "+n("t");case "%C":return Math.floor(f.getFullYear()/
109
- 100+1);case "%D":return n("MM/dd/yy");case "%n":return"\\n";case "%t":return"\\t";case "%r":return n("hh:mm tt");case "%R":return n("H:mm");case "%T":return n("H:mm:ss");case "%x":return n("d");case "%X":return n("t");default:d.push(k);return k}}):this._toString()};if(!b.format)b.format=b.$format})();
1
  var humanMsg={setup:function(a,b){humanMsg.msgID="humanMsg";humanMsg.logID="humanMsgLog";if(a==undefined)a="body";humanMsg.msgOpacity=0.8;if(b!=undefined)humanMsg.msgOpacity=parseFloat(b);jQuery(a).append('<div id="'+humanMsg.msgID+'" class="humanMsg"><div class="round"></div><p></p><div class="round"></div></div>');jQuery("#"+humanMsg.logID+" p").click(function(){jQuery(this).siblings("ul").slideToggle()})},displayMsg:function(a){if(a!=""){clearTimeout(humanMsg.t2);jQuery("#"+humanMsg.msgID+" p").html(a);
2
  jQuery("#"+humanMsg.msgID+"").show().animate({opacity:humanMsg.msgOpacity},200,function(){jQuery("#"+humanMsg.logID).show().children("ul").prepend("<li>"+a+"</li>").children("li:first").slideDown(200);jQuery("#"+humanMsg.logID+" ul").css("display")=="none"&&jQuery("#"+humanMsg.logID+" p").animate({bottom:40},200,"linear",function(){jQuery(this).animate({bottom:0},300,"easeOutBounce",function(){jQuery(this).css({bottom:0})})})});humanMsg.t1=setTimeout("humanMsg.bindEvents()",700);humanMsg.t2=setTimeout("humanMsg.removeMsg()",
3
+ 5000)}},bindEvents:function(){jQuery(window).mousemove(humanMsg.removeMsg).click(humanMsg.removeMsg).keypress(humanMsg.removeMsg)},removeMsg:function(){jQuery(window).unbind("mousemove",humanMsg.removeMsg).unbind("click",humanMsg.removeMsg).unbind("keypress",humanMsg.removeMsg);jQuery("#"+humanMsg.msgID).css("opacity")==humanMsg.msgOpacity&&jQuery("#"+humanMsg.msgID).animate({opacity:0},500,function(){jQuery(this).hide()})}};jQuery(document).ready(function(){humanMsg.setup()});var sprintf=function(){function a(c){return Object.prototype.toString.call(c).slice(8,-1).toLowerCase()}function b(c,e){for(var g=[];e>0;g[--e]=c);return g.join("")}function d(){d.cache.hasOwnProperty(arguments[0])||(d.cache[arguments[0]]=d.parse(arguments[0]));return d.format.call(null,d.cache[arguments[0]],arguments)}d.format=function(c,e){var g=1,n=c.length,m="",l=[],f,h,k,o;for(f=0;f<n;f++){m=a(c[f]);if(m==="string")l.push(c[f]);else if(m==="array"){k=c[f];if(k[2]){m=e[g];for(h=0;h<k[2].length;h++){if(!m.hasOwnProperty(k[2][h]))throw sprintf('[sprintf] property "%s" does not exist',
4
+ k[2][h]);m=m[k[2][h]]}}else m=k[1]?e[k[1]]:e[g++];if(/[^s]/.test(k[8])&&a(m)!="number")throw sprintf("[sprintf] expecting number but found %s",a(m));switch(k[8]){case "b":m=m.toString(2);break;case "c":m=String.fromCharCode(m);break;case "d":m=parseInt(m,10);break;case "e":m=k[7]?m.toExponential(k[7]):m.toExponential();break;case "f":m=k[7]?parseFloat(m).toFixed(k[7]):parseFloat(m);break;case "o":m=m.toString(8);break;case "s":m=(m=String(m))&&k[7]?m.substring(0,k[7]):m;break;case "u":m=Math.abs(m);
5
+ break;case "x":m=m.toString(16);break;case "X":m=m.toString(16).toUpperCase();break}m=/[def]/.test(k[8])&&k[3]&&m>=0?"+"+m:m;h=k[4]?k[4]=="0"?"0":k[4].charAt(1):" ";o=k[6]-String(m).length;h=k[6]?b(h,o):"";l.push(k[5]?m+h:h+m)}}return l.join("")};d.cache={};d.parse=function(c){var e=c;c=[];for(var g=[],n=0;e;){if((c=/^[^\x25]+/.exec(e))!==null)g.push(c[0]);else if((c=/^\x25{2}/.exec(e))!==null)g.push("%");else if((c=/^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(e))!==
6
+ null){if(c[2]){n|=1;var m=[],l=c[2],f=[];if((f=/^([a-z_][a-z_\d]*)/i.exec(l))!==null)for(m.push(f[1]);(l=l.substring(f[0].length))!=="";)if((f=/^\.([a-z_][a-z_\d]*)/i.exec(l))!==null)m.push(f[1]);else if((f=/^\[(\d+)\]/.exec(l))!==null)m.push(f[1]);else throw"[sprintf] huh?";else throw"[sprintf] huh?";c[2]=m}else n|=2;if(n===3)throw"[sprintf] mixing positional and named placeholders is not (yet) supported";g.push(c)}else throw"[sprintf] huh?";e=e.substring(c[0].length)}return g};return d}();
7
+ function vsprintf(a,b){b.unshift(a);return sprintf.apply(null,b)};jQuery.cookie=function(a,b,d){if(typeof b!="undefined"){d=d||{};if(b===null){b="";d.expires=-1}var c="";if(d.expires&&(typeof d.expires=="number"||d.expires.toUTCString)){if(typeof d.expires=="number"){c=new Date;c.setTime(c.getTime()+d.expires*24*60*60*1000)}else c=d.expires;c="; expires="+c.toUTCString()}var e=d.path?"; path="+d.path:"",g=d.domain?"; domain="+d.domain:"";d=d.secure?"; secure":"";document.cookie=[a,"=",encodeURIComponent(b),c,e,g,d].join("")}else{b=null;if(document.cookie&&document.cookie!=
8
  ""){d=document.cookie.split(";");for(c=0;c<d.length;c++){e=jQuery.trim(d[c]);if(e.substring(0,a.length+1)==a+"="){b=decodeURIComponent(e.substring(a.length+1));break}}}return b}};(function(a){a.fn.bgIframe=a.fn.bgiframe=function(b){if(a.browser.msie&&parseInt(a.browser.version)<=6){b=a.extend({top:"auto",left:"auto",width:"auto",height:"auto",opacity:true,src:"javascript:false;"},b||{});var d=function(e){return e&&e.constructor==Number?e+"px":e},c='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+b.src+'"style="display:block;position:absolute;z-index:-1;'+(b.opacity!==false?"filter:Alpha(Opacity='0');":"")+"top:"+(b.top=="auto"?"expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+'px')":
9
+ d(b.top))+";left:"+(b.left=="auto"?"expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+'px')":d(b.left))+";width:"+(b.width=="auto"?"expression(this.parentNode.offsetWidth+'px')":d(b.width))+";height:"+(b.height=="auto"?"expression(this.parentNode.offsetHeight+'px')":d(b.height))+';"/>';return this.each(function(){a("> iframe.bgiframe",this).length==0&&this.insertBefore(document.createElement(c),this.firstChild)})}return this};if(!a.browser.version)a.browser.version=navigator.userAgent.toLowerCase().match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)[1]})(jQuery);(function(a){a.each({focus:"focusin",blur:"focusout"},function(b,d){a.event.special[d]={setup:function(){if(a.browser.msie)return false;this.addEventListener(b,a.event.special[d].handler,true)},teardown:function(){if(a.browser.msie)return false;this.removeEventListener(b,a.event.special[d].handler,true)},handler:function(c){arguments[0]=a.event.fix(c);arguments[0].type=d;return a.event.handle.apply(this,arguments)}}});a.extend(a.fn,{delegate:function(b,d,c){return this.bind(b,function(e){var g=a(e.target);
10
+ if(g.is(d))return c.apply(g,arguments)})},triggerEvent:function(b,d){return this.triggerHandler(b,[a.event.fix({type:b,target:d})])}})})(jQuery);(function(a){a.tools=a.tools||{};a.tools.scrollable={version:"1.1.2",conf:{size:5,vertical:false,speed:400,keyboard:true,keyboardSteps:null,disabledClass:"disabled",hoverClass:null,clickable:true,activeClass:"active",easing:"swing",loop:false,items:".items",item:null,prev:".prev",next:".next",prevPage:".prevPage",nextPage:".nextPage",api:false}};var b;function d(c,e){var g=this,n=a(this),m=!e.vertical,l=c.children(),f=0,h;b||(b=g);a.each(e,function(i,j){a.isFunction(j)&&n.bind(i,j)});if(l.length>
11
+ 1)l=a(e.items,c);function k(i){var j=a(i);return e.globalNav?j:c.parent().find(i)}c.data("finder",k);var o=k(e.prev),r=k(e.next),q=k(e.prevPage),p=k(e.nextPage);a.extend(g,{getIndex:function(){return f},getClickIndex:function(){var i=g.getItems();return i.index(i.filter("."+e.activeClass))},getConf:function(){return e},getSize:function(){return g.getItems().size()},getPageAmount:function(){return Math.ceil(this.getSize()/e.size)},getPageIndex:function(){return Math.ceil(f/e.size)},getNaviButtons:function(){return o.add(r).add(q).add(p)},
12
+ getRoot:function(){return c},getItemWrap:function(){return l},getItems:function(){return l.children(e.item)},getVisibleItems:function(){return g.getItems().slice(f,f+e.size)},seekTo:function(i,j,s){if(i<0)i=0;if(f===i)return g;if(a.isFunction(j))s=j;if(i>g.getSize()-e.size)return e.loop?g.begin():this.end();var u=g.getItems().eq(i);if(!u.length)return g;var w=a.Event("onBeforeSeek");n.trigger(w,[i]);if(w.isDefaultPrevented())return g;if(j===undefined||a.isFunction(j))j=e.speed;function x(){s&&s.call(g,
13
+ i);n.trigger("onSeek",[i])}m?l.animate({left:-u.position().left},j,e.easing,x):l.animate({top:-u.position().top},j,e.easing,x);b=g;f=i;w=a.Event("onStart");n.trigger(w,[i]);if(w.isDefaultPrevented())return g;o.add(q).toggleClass(e.disabledClass,i===0);r.add(p).toggleClass(e.disabledClass,i>=g.getSize()-e.size);return g},move:function(i,j,s){h=i>0;return this.seekTo(f+i,j,s)},next:function(i,j){return this.move(1,i,j)},prev:function(i,j){return this.move(-1,i,j)},movePage:function(i,j,s){h=i>0;var u=
14
+ e.size*i,w=f%e.size;if(w>0)u+=i>0?-w:e.size-w;return this.move(u,j,s)},prevPage:function(i,j){return this.movePage(-1,i,j)},nextPage:function(i,j){return this.movePage(1,i,j)},setPage:function(i,j,s){return this.seekTo(i*e.size,j,s)},begin:function(i,j){h=false;return this.seekTo(0,i,j)},end:function(i,j){h=true;var s=this.getSize()-e.size;return s>0?this.seekTo(s,i,j):g},reload:function(){n.trigger("onReload");return g},focus:function(){return b=g},click:function(i){var j=g.getItems().eq(i),s=e.activeClass,
15
+ u=e.size;if(i<0||i>=g.getSize())return g;if(u==1){if(e.loop)return g.next();if(i===0||i==g.getSize()-1)h=h===undefined?true:!h;return h===false?g.prev():g.next()}if(u==2){i==f&&i--;g.getItems().removeClass(s);j.addClass(s);return g.seekTo(i,time,fn)}if(!j.hasClass(s)){g.getItems().removeClass(s);j.addClass(s);j=Math.floor(u/2);j=i-j;if(j>g.getSize()-u)j=g.getSize()-u;if(j!==i)return g.seekTo(j)}return g},bind:function(i,j){n.bind(i,j);return g},unbind:function(i){n.unbind(i);return g}});a.each("onBeforeSeek,onStart,onSeek,onReload".split(","),
16
+ function(i,j){g[j]=function(s){return g.bind(j,s)}});o.addClass(e.disabledClass).click(function(){g.prev()});r.click(function(){g.next()});p.click(function(){g.nextPage()});g.getSize()<e.size&&r.add(p).addClass(e.disabledClass);q.addClass(e.disabledClass).click(function(){g.prevPage()});var t=e.hoverClass,v="keydown."+Math.random().toString().substring(10);g.onReload(function(){t&&g.getItems().hover(function(){a(this).addClass(t)},function(){a(this).removeClass(t)});e.clickable&&g.getItems().each(function(i){a(this).unbind("click.scrollable").bind("click.scrollable",
17
+ function(j){if(!a(j.target).is("a"))return g.click(i)})});e.keyboard?a(document).unbind(v).bind(v,function(i){if(!(i.altKey||i.ctrlKey))if(!(e.keyboard!="static"&&b!=g)){var j=e.keyboardSteps;if(m&&(i.keyCode==37||i.keyCode==39)){g.move(i.keyCode==37?-j:j);return i.preventDefault()}if(!m&&(i.keyCode==38||i.keyCode==40)){g.move(i.keyCode==38?-j:j);return i.preventDefault()}return true}}):a(document).unbind(v)});g.reload()}a.fn.scrollable=function(c){var e=this.eq(typeof c=="number"?c:0).data("scrollable");
18
+ if(e)return e;var g=a.extend({},a.tools.scrollable.conf);c=a.extend(g,c);c.keyboardSteps=c.keyboardSteps||c.size;this.each(function(){e=new d(a(this),c);a(this).data("scrollable",e)});return c.api?e:this}})(jQuery);
19
+ (function(a){var b=a.tools.scrollable;b.plugins=b.plugins||{};b.plugins.autoscroll={version:"1.0.1",conf:{autoplay:true,interval:3000,autopause:true,steps:1,api:false}};a.fn.autoscroll=function(d){if(typeof d=="number")d={interval:d};var c=a.extend({},b.plugins.autoscroll.conf),e;a.extend(c,d);this.each(function(){var g=a(this).scrollable();if(g)e=g;var n,m,l=true;g.play=function(){if(!n){l=false;n=setInterval(function(){g.move(c.steps)},c.interval);g.move(c.steps)}};g.pause=function(){n=clearInterval(n)};
20
+ g.stop=function(){g.pause();l=true};c.autopause&&g.getRoot().add(g.getNaviButtons()).hover(function(){g.pause();clearInterval(m)},function(){l||(m=setTimeout(g.play,c.interval))});c.autoplay&&setTimeout(g.play,c.interval)});return c.api?e:this}})(jQuery);
21
+ (function(a){var b=a.tools.scrollable;b.plugins=b.plugins||{};b.plugins.navigator={version:"1.0.2",conf:{navi:".navi",naviItem:null,activeClass:"active",indexed:false,api:false,idPrefix:null}};a.fn.navigator=function(d){var c=a.extend({},b.plugins.navigator.conf),e;if(typeof d=="string")d={navi:d};d=a.extend(c,d);this.each(function(){var g=a(this).scrollable(),n=g.getRoot(),m=n.data("finder").call(null,d.navi),l=null,f=g.getNaviButtons();if(g)e=g;g.getNaviButtons=function(){return f.add(m)};function h(){if(!m.children().length||
22
+ m.data("navi")==g){m.empty();m.data("navi",g);for(var k=0;k<g.getPageAmount();k++)m.append(a("<"+(d.naviItem||"a")+"/>"));l=m.children().each(function(o){var r=a(this);r.click(function(q){g.setPage(o);return q.preventDefault()});d.indexed&&r.text(o);d.idPrefix&&r.attr("id",d.idPrefix+o)})}else{l=d.naviItem?m.find(d.naviItem):m.children();l.each(function(o){var r=a(this);r.click(function(q){g.setPage(o);return q.preventDefault()})})}l.eq(0).addClass(d.activeClass)}g.onStart(function(){var k=d.activeClass;
23
+ l.removeClass(k).eq(g.getPageIndex()).addClass(k)});g.onReload(function(){h()});h();n=l.filter("[href="+location.hash+"]");n.length&&g.move(l.index(n))});return d.api?e:this}})(jQuery);
24
  (function(a){a.fn.wheel=function(e){return this[e?"bind":"trigger"]("wheel",e)};a.event.special.wheel={setup:function(){a.event.add(this,b,d,{})},teardown:function(){a.event.remove(this,b,d)}};var b=!a.browser.mozilla?"mousewheel":"DOMMouseScroll"+(a.browser.version<"1.9"?" mousemove":"");function d(e){switch(e.type){case "mousemove":return a.extend(e.data,{clientX:e.clientX,clientY:e.clientY,pageX:e.pageX,pageY:e.pageY});case "DOMMouseScroll":a.extend(e,e.data);e.delta=-e.detail/3;break;case "mousewheel":e.delta=
25
+ e.wheelDelta/120;break}e.type="wheel";return a.event.handle.call(this,e,e.delta)}var c=a.tools.scrollable;c.plugins=c.plugins||{};c.plugins.mousewheel={version:"1.0.1",conf:{api:false,speed:50}};a.fn.mousewheel=function(e){var g=a.extend({},c.plugins.mousewheel.conf),n;if(typeof e=="number")e={speed:e};e=a.extend(g,e);this.each(function(){var m=a(this).scrollable();if(m)n=m;m.getRoot().wheel(function(l,f){m.move(f<0?1:-1,e.speed||50);return false})});return e.api?n:this}})(jQuery);(function(a){a.fn.timePicker=function(l){var f=a.extend({},a.fn.timePicker.defaults,l);return this.each(function(){a.timePicker(this,f)})};a.timePicker=function(l,f){l=a(l)[0];return l.timePicker||(l.timePicker=new jQuery._timePicker(l,f))};a._timePicker=function(l,f){var h=false,k=false,o=g(f.startTime,f),r=g(f.endTime,f);a(l).attr("autocomplete","OFF");for(var q=[],p=new Date(o);p<=r;){q[q.length]=d(p,f);p=new Date(p.setMinutes(p.getMinutes()+f.step))}var t=a("<div "+(f.tpDivId?'id="'+f.tpDivId+
26
+ '" ':"")+'class="time-picker'+(f.show24Hours?"":" time-picker-12hours")+'"></div>'),v=a("<ul></ul>");for(p=0;p<q.length;p++)v.append("<li>"+q[p]+"</li>");t.append(v);q=a(l).offset();t.appendTo("body").css({top:q.top-48+"px",left:q.left,width:a(l).width()+5+"px"}).hide();t.mouseover(function(){h=true}).mouseout(function(){h=false});a("li",v).mouseover(function(){if(!k){a("li.selected",t).removeClass("selected");a(this).addClass("selected")}}).mousedown(function(){h=true}).click(function(){b(l,this,
27
+ t,f);h=false});function i(){if(t.is(":visible"))return false;a("li",t).removeClass("selected");var j=a(l).offset();t.css({top:j.top-48+"px",left:j.left,width:a(l).width()+5+"px"});t.show();var s=l.value?n(l.value,f):o;j=o.getHours()*60+o.getMinutes();s=s.getHours()*60+s.getMinutes()-j;s=Math.round(s/f.step);j=m(new Date(0,0,0,0,s*f.step+j,0));j=o<j&&j<=r?j:o;j=a("li:contains("+d(j,f)+")",t);if(j.length){j.addClass("selected");t[0].scrollTop=j[0].offsetTop}return true}a(l).focus(i).click(i);a(l).blur(function(){h||
28
+ t.hide()});q=a.browser.opera||a.browser.mozilla?"keypress":"keydown";a(l)[q](function(j){k=true;var s=t[0].scrollTop;switch(j.keyCode){case 38:if(i())return false;j=a("li.selected",v);var u=j.prev().addClass("selected")[0];if(u){j.removeClass("selected");if(u.offsetTop<s)t[0].scrollTop=s-u.offsetHeight}else{j.removeClass("selected");u=a("li:last",v).addClass("selected")[0];t[0].scrollTop=u.offsetTop-u.offsetHeight}return false;case 40:if(i())return false;j=a("li.selected",v);if(u=j.next().addClass("selected")[0]){j.removeClass("selected");
29
+ if(u.offsetTop+u.offsetHeight>s+t[0].offsetHeight)t[0].scrollTop=s+u.offsetHeight}else{j.removeClass("selected");a("li:first",v).addClass("selected");t[0].scrollTop=0}return false;case 13:if(t.is(":visible")){s=a("li.selected",v)[0];b(l,s,t,f)}return false;case 27:t.hide();return false}return true});a(l).keyup(function(){k=false});this.getTime=function(){return n(l.value,f)};this.setTime=function(j){l.value=d(m(j),f);a(l).change()}};a.fn.timePicker.defaults={step:30,startTime:new Date(0,0,0,0,0,0),
30
+ endTime:new Date(0,0,0,23,30,0),separator:":",show24Hours:true};function b(l,f,h){l.value=a(f).text();a(l).change();a.browser.msie||l.focus();h.hide()}function d(l,f){var h=l.getHours(),k=f.show24Hours?h:(h+11)%12+1;k=e(k,f);l=l.getMinutes();return k+f.separator+c(l)+(f.show24Hours?"":h<12?" AM":" PM")}function c(l){return(l<10?"0":"")+l}function e(l,f){return f.show24Hours?(l<10?"0":"")+l:l}function g(l,f){return typeof l=="object"?m(l):n(l,f)}function n(l,f){if(l){var h=l.split(f.separator),k=parseFloat(h[0]);
31
+ h=parseFloat(h[1]);if(!f.show24Hours)if(k===12&&l.substr("AM")!==-1)k=0;else if(k!==12&&l.indexOf("PM")!==-1)k+=12;l=new Date(0,0,0,k,h,0);return m(l)}return null}function m(l){l.setFullYear(2001);l.setMonth(0);l.setDate(0);return l}})(jQuery);if(!this.JSON)this.JSON={};
32
+ (function(){function a(f){return f<10?"0"+f:f}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+a(this.getUTCMonth()+1)+"-"+a(this.getUTCDate())+"T"+a(this.getUTCHours())+":"+a(this.getUTCMinutes())+":"+a(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()}}var b=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,d=
33
+ /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,c,e,g={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},n;function m(f){d.lastIndex=0;return d.test(f)?'"'+f.replace(d,function(h){var k=g[h];return typeof k==="string"?k:"\\u"+("0000"+h.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+f+'"'}function l(f,h){var k,o,r=c,q,p=h[f];if(p&&typeof p==="object"&&typeof p.toJSON==="function")p=p.toJSON(f);
34
+ if(typeof n==="function")p=n.call(h,f,p);switch(typeof p){case "string":return m(p);case "number":return isFinite(p)?String(p):"null";case "boolean":case "null":return String(p);case "object":if(!p)return"null";c+=e;q=[];if(Object.prototype.toString.apply(p)==="[object Array]"){o=p.length;for(f=0;f<o;f+=1)q[f]=l(f,p)||"null";h=q.length===0?"[]":c?"[\n"+c+q.join(",\n"+c)+"\n"+r+"]":"["+q.join(",")+"]";c=r;return h}if(n&&typeof n==="object"){o=n.length;for(f=0;f<o;f+=1){k=n[f];if(typeof k==="string")if(h=
35
+ l(k,p))q.push(m(k)+(c?": ":":")+h)}}else for(k in p)if(Object.hasOwnProperty.call(p,k))if(h=l(k,p))q.push(m(k)+(c?": ":":")+h);h=q.length===0?"{}":c?"{\n"+c+q.join(",\n"+c)+"\n"+r+"}":"{"+q.join(",")+"}";c=r;return h}}if(typeof JSON.stringify!=="function")JSON.stringify=function(f,h,k){var o;e=c="";if(typeof k==="number")for(o=0;o<k;o+=1)e+=" ";else if(typeof k==="string")e=k;if((n=h)&&typeof h!=="function"&&(typeof h!=="object"||typeof h.length!=="number"))throw new Error("JSON.stringify");return l("",
36
+ {"":f})};if(typeof JSON.parseIt!=="function")JSON.parseIt=function(f,h){function k(o,r){var q,p,t=o[r];if(t&&typeof t==="object")for(q in t)if(Object.hasOwnProperty.call(t,q)){p=k(t,q);if(p!==undefined)t[q]=p;else delete t[q]}return h.call(o,r,t)}b.lastIndex=0;if(b.test(f))f=f.replace(b,function(o){return"\\u"+("0000"+o.charCodeAt(0).toString(16)).slice(-4)});if(/^[\],:{}\s]*$/.test(f.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
37
+ "]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){f=eval("("+f+")");return typeof h==="function"?k({"":f},""):f}throw new SyntaxError("JSON.parseIt");}})();(function(a){a.tools=a.tools||{};a.tools.scrollable={version:"1.1.2",conf:{size:5,vertical:false,speed:400,keyboard:true,keyboardSteps:null,disabledClass:"disabled",hoverClass:null,clickable:true,activeClass:"active",easing:"swing",loop:false,items:".items",item:null,prev:".prev",next:".next",prevPage:".prevPage",nextPage:".nextPage",api:false}};var b;function d(c,e){var g=this,n=a(this),m=!e.vertical,l=c.children(),f=0,h;b||(b=g);a.each(e,function(i,j){a.isFunction(j)&&n.bind(i,j)});if(l.length>
38
+ 1)l=a(e.items,c);function k(i){var j=a(i);return e.globalNav?j:c.parent().find(i)}c.data("finder",k);var o=k(e.prev),r=k(e.next),q=k(e.prevPage),p=k(e.nextPage);a.extend(g,{getIndex:function(){return f},getClickIndex:function(){var i=g.getItems();return i.index(i.filter("."+e.activeClass))},getConf:function(){return e},getSize:function(){return g.getItems().size()},getPageAmount:function(){return Math.ceil(this.getSize()/e.size)},getPageIndex:function(){return Math.ceil(f/e.size)},getNaviButtons:function(){return o.add(r).add(q).add(p)},
39
+ getRoot:function(){return c},getItemWrap:function(){return l},getItems:function(){return l.children(e.item)},getVisibleItems:function(){return g.getItems().slice(f,f+e.size)},seekTo:function(i,j,s){if(i<0)i=0;if(f===i)return g;if(a.isFunction(j))s=j;if(i>g.getSize()-e.size)return e.loop?g.begin():this.end();var u=g.getItems().eq(i);if(!u.length)return g;var w=a.Event("onBeforeSeek");n.trigger(w,i>f);if(w.isDefaultPrevented())return g;if(j===undefined||a.isFunction(j))j=e.speed;function x(){s&&s.call(g,
40
+ i);n.trigger("onSeek",[i])}m?l.animate({left:-u.position().left},j,e.easing,x):l.animate({top:-u.position().top},j,e.easing,x);b=g;f=i;w=a.Event("onStart");n.trigger(w,[i]);if(w.isDefaultPrevented())return g;o.add(q).toggleClass(e.disabledClass,i===0);r.add(p).toggleClass(e.disabledClass,i>=g.getSize()-e.size);return g},move:function(i,j,s){h=i>0;return this.seekTo(f+i,j,s)},next:function(i,j){return this.move(1,i,j)},prev:function(i,j){return this.move(-1,i,j)},movePage:function(i,j,s){h=i>0;var u=
41
+ e.size*i,w=f%e.size;if(w>0)u+=i>0?-w:e.size-w;return this.move(u,j,s)},prevPage:function(i,j){return this.movePage(-1,i,j)},nextPage:function(i,j){return this.movePage(1,i,j)},setPage:function(i,j,s){return this.seekTo(i*e.size,j,s)},begin:function(i,j){h=false;return this.seekTo(0,i,j)},end:function(i,j){h=true;var s=this.getSize()-e.size;return s>0?this.seekTo(s,i,j):g},reload:function(){n.trigger("onReload");return g},focus:function(){return b=g},click:function(i){var j=g.getItems().eq(i),s=e.activeClass,
42
+ u=e.size;if(i<0||i>=g.getSize())return g;if(u==1){if(e.loop)return g.next();if(i===0||i==g.getSize()-1)h=h===undefined?true:!h;return h===false?g.prev():g.next()}if(u==2){i==f&&i--;g.getItems().removeClass(s);j.addClass(s);return g.seekTo(i,time,fn)}if(!j.hasClass(s)){g.getItems().removeClass(s);j.addClass(s);j=Math.floor(u/2);j=i-j;if(j>g.getSize()-u)j=g.getSize()-u;if(j!==i)return g.seekTo(j)}return g},bind:function(i,j){n.bind(i,j);return g},unbind:function(i){n.unbind(i);return g}});a.each("onBeforeSeek,onStart,onSeek,onReload".split(","),
43
+ function(i,j){g[j]=function(s){return g.bind(j,s)}});o.addClass(e.disabledClass).click(function(){g.prev()});r.click(function(){g.next()});p.click(function(){g.nextPage()});g.getSize()<e.size&&r.add(p).addClass(e.disabledClass);q.addClass(e.disabledClass).click(function(){g.prevPage()});var t=e.hoverClass,v="keydown."+Math.random().toString().substring(10);g.onReload(function(){t&&g.getItems().hover(function(){a(this).addClass(t)},function(){a(this).removeClass(t)});e.clickable&&g.getItems().each(function(i){a(this).unbind("click.scrollable").bind("click.scrollable",
44
+ function(j){if(!a(j.target).is("a"))return g.click(i)})});e.keyboard?a(document).unbind(v).bind(v,function(i){if(!(i.altKey||i.ctrlKey))if(!(e.keyboard!="static"&&b!=g)){var j=e.keyboardSteps;if(m&&(i.keyCode==37||i.keyCode==39)){g.move(i.keyCode==37?-j:j);return i.preventDefault()}if(!m&&(i.keyCode==38||i.keyCode==40)){g.move(i.keyCode==38?-j:j);return i.preventDefault()}return true}}):a(document).unbind(v)});g.reload()}a.fn.scrollable=function(c){var e=this.eq(typeof c=="number"?c:0).data("scrollable");
45
+ if(e)return e;var g=a.extend({},a.tools.scrollable.conf);c=a.extend(g,c);c.keyboardSteps=c.keyboardSteps||c.size;this.each(function(){e=new d(a(this),c);a(this).data("scrollable",e)});return c.api?e:this}})(jQuery);(function(a){a.fn.wheel=function(e){return this[e?"bind":"trigger"]("wheel",e)};a.event.special.wheel={setup:function(){a.event.add(this,b,d,{})},teardown:function(){a.event.remove(this,b,d)}};var b=!a.browser.mozilla?"mousewheel":"DOMMouseScroll"+(a.browser.version<"1.9"?" mousemove":"");function d(e){switch(e.type){case "mousemove":return a.extend(e.data,{clientX:e.clientX,clientY:e.clientY,pageX:e.pageX,pageY:e.pageY});case "DOMMouseScroll":a.extend(e,e.data);e.delta=-e.detail/3;break;case "mousewheel":e.delta=
46
+ e.wheelDelta/120;break}e.type="wheel";return a.event.handle.call(this,e,e.delta)}var c=a.tools.scrollable;c.plugins=c.plugins||{};c.plugins.mousewheel={version:"1.0.1",conf:{api:false,speed:50}};a.fn.mousewheel=function(e){var g=a.extend({},c.plugins.mousewheel.conf),n;if(typeof e=="number")e={speed:e};e=a.extend(g,e);this.each(function(){var m=a(this).scrollable();if(m)n=m;m.getRoot().wheel(function(l,f){m.move(f<0?1:-1,e.speed||50);return false})});return e.api?n:this}})(jQuery);jQuery.ui||function(a){var b=a.fn.remove,d=a.browser.mozilla&&parseFloat(a.browser.version)<1.9;a.ui={version:"1.7.2",plugin:{add:function(f,h,k){f=a.ui[f].prototype;for(var o in k){f.plugins[o]=f.plugins[o]||[];f.plugins[o].push([h,k[o]])}},call:function(f,h,k){if((h=f.plugins[h])&&f.element[0].parentNode)for(var o=0;o<h.length;o++)f.options[h[o][0]]&&h[o][1].apply(f.element,k)}},contains:function(f,h){return document.compareDocumentPosition?f.compareDocumentPosition(h)&16:f!==h&&f.contains(h)},
47
+ hasScroll:function(f,h){if(a(f).css("overflow")=="hidden")return false;h=h&&h=="left"?"scrollLeft":"scrollTop";var k=false;if(f[h]>0)return true;f[h]=1;k=f[h]>0;f[h]=0;return k},isOverAxis:function(f,h,k){return f>h&&f<h+k},isOver:function(f,h,k,o,r,q){return a.ui.isOverAxis(f,k,r)&&a.ui.isOverAxis(h,o,q)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,
48
+ NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var c=a.attr,e=a.fn.removeAttr,g="http://www.w3.org/2005/07/aaa",n=/^aria-/,m=/^wairole:/;a.attr=function(f,h,k){var o=k!==undefined;return h=="role"?o?c.call(this,f,h,"wairole:"+k):(c.apply(this,arguments)||"").replace(m,""):n.test(h)?o?f.setAttributeNS(g,h.replace(n,"aaa:"),k):c.call(this,f,h.replace(n,"aaa:")):c.apply(this,arguments)};a.fn.removeAttr=function(f){return n.test(f)?
49
+ this.each(function(){this.removeAttributeNS(g,f.replace(n,""))}):e.call(this,f)}}a.fn.extend({remove:function(){a("*",this).add(this).each(function(){a(this).triggerHandler("remove")});return b.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var f;
50
+ f=a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||
51
+ !f.length?a(document):f}});a.extend(a.expr[":"],{data:function(f,h,k){return!!a.data(f,k[3])},focusable:function(f){var h=f.nodeName.toLowerCase(),k=a.attr(f,"tabindex");return(/input|select|textarea|button|object/.test(h)?!f.disabled:"a"==h||"area"==h?f.href||!isNaN(k):!isNaN(k))&&!a(f)["area"==h?"parents":"closest"](":hidden").length},tabbable:function(f){var h=a.attr(f,"tabindex");return(isNaN(h)||h>=0)&&a(f).is(":focusable")}});function l(f,h,k,o){function r(p){p=a[f][h][p]||[];return typeof p==
52
+ "string"?p.split(/,?\s+/):p}var q=r("getter");if(o.length==1&&typeof o[0]=="string")q=q.concat(r("getterSetter"));return a.inArray(k,q)!=-1}a.widget=function(f,h){var k=f.split(".")[0];f=f.split(".")[1];a.fn[f]=function(o){var r=typeof o=="string",q=Array.prototype.slice.call(arguments,1);if(r&&o.substring(0,1)=="_")return this;if(r&&l(k,f,o,q)){var p=a.data(this[0],f);return p?p[o].apply(p,q):undefined}return this.each(function(){var t=a.data(this,f);!t&&!r&&a.data(this,f,new a[k][f](this,o))._init();
53
+ t&&r&&a.isFunction(t[o])&&t[o].apply(t,q)})};a[k]=a[k]||{};a[k][f]=function(o,r){var q=this;this.namespace=k;this.widgetName=f;this.widgetEventPrefix=a[k][f].eventPrefix||f;this.widgetBaseClass=k+"-"+f;this.options=a.extend({},a.widget.defaults,a[k][f].defaults,a.metadata&&a.metadata.get(o)[f],r);this.element=a(o).bind("setData."+f,function(p,t,v){if(p.target==o)return q._setData(t,v)}).bind("getData."+f,function(p,t){if(p.target==o)return q._getData(t)}).bind("remove",function(){return q.destroy()})};
54
+ a[k][f].prototype=a.extend({},a.widget.prototype,h);a[k][f].getterSetter="option"};a.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(f,h){var k=f,o=this;if(typeof f=="string"){if(h===undefined)return this._getData(f);k={};k[f]=h}a.each(k,function(r,q){o._setData(r,q)})},_getData:function(f){return this.options[f]},_setData:function(f,
55
+ h){this.options[f]=h;if(f=="disabled")this.element[h?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",h)},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(f,h,k){var o=this.options[f];f=f==this.widgetEventPrefix?f:this.widgetEventPrefix+f;h=a.Event(h);h.type=f;if(h.originalEvent){f=a.event.props.length;for(var r;f;){r=a.event.props[--f];h[r]=h.originalEvent[r]}}this.element.trigger(h,
56
+ k);return!(a.isFunction(o)&&o.call(this.element[0],h,k)===false||h.isDefaultPrevented())}};a.widget.defaults={disabled:false};a.ui.mouse={_mouseInit:function(){var f=this;this.element.bind("mousedown."+this.widgetName,function(h){return f._mouseDown(h)}).bind("click."+this.widgetName,function(h){if(f._preventClickEvent){f._preventClickEvent=false;h.stopImmediatePropagation();return false}});if(a.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable",
57
+ "on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);a.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable)},_mouseDown:function(f){f.originalEvent=f.originalEvent||{};if(!f.originalEvent.mouseHandled){this._mouseStarted&&this._mouseUp(f);this._mouseDownEvent=f;var h=this,k=f.which==1,o=typeof this.options.cancel=="string"?a(f.target).parents().add(f.target).filter(this.options.cancel).length:false;if(!k||o||!this._mouseCapture(f))return true;
58
+ this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){h.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(f)&&this._mouseDelayMet(f)){this._mouseStarted=this._mouseStart(f)!==false;if(!this._mouseStarted){f.preventDefault();return true}}this._mouseMoveDelegate=function(r){return h._mouseMove(r)};this._mouseUpDelegate=function(r){return h._mouseUp(r)};a(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+
59
+ this.widgetName,this._mouseUpDelegate);a.browser.safari||f.preventDefault();return f.originalEvent.mouseHandled=true}},_mouseMove:function(f){if(a.browser.msie&&!f.button)return this._mouseUp(f);if(this._mouseStarted){this._mouseDrag(f);return f.preventDefault()}if(this._mouseDistanceMet(f)&&this._mouseDelayMet(f))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,f)!==false)?this._mouseDrag(f):this._mouseUp(f);return!this._mouseStarted},_mouseUp:function(f){a(document).unbind("mousemove."+
60
+ this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=f.target==this._mouseDownEvent.target;this._mouseStop(f)}return false},_mouseDistanceMet:function(f){return Math.max(Math.abs(this._mouseDownEvent.pageX-f.pageX),Math.abs(this._mouseDownEvent.pageY-f.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},
61
  _mouseStop:function(){},_mouseCapture:function(){return true}};a.ui.mouse.defaults={cancel:null,distance:1,delay:0}}(jQuery);(function(a){a.widget("ui.draggable",a.extend({},a.ui.mouse,{_init:function(){if(this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");
62
  this._mouseDestroy()}},_mouseCapture:function(b){var d=this.options;if(this.helper||d.disabled||a(b.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(b);if(!this.handle)return false;return true},_mouseStart:function(b){var d=this.options;this.helper=this._createHelper(b);this._cacheHelperProportions();if(a.ui.ddmanager)a.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.element.offset();
63
  this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(b);this.originalPageX=b.pageX;this.originalPageY=b.pageY;d.cursorAt&&this._adjustOffsetFromHelper(d.cursorAt);d.containment&&this._setContainment();this._trigger("start",b);this._cacheHelperProportions();a.ui.ddmanager&&
72
  10)||0)+(parseInt(a(d).css("paddingTop"),10)||0)-this.margins.top,b.left+(c?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,b.top+(c?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}}else if(b.containment.constructor==
73
  Array)this.containment=b.containment},_convertPositionTo:function(b,d){if(!d)d=this.position;b=b=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:d.top+this.offset.relative.top*b+this.offset.parent.top*b-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*
74
  b),left:d.left+this.offset.relative.left*b+this.offset.parent.left*b-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())*b)}},_generatePosition:function(b){var d=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=
75
+ document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset();var g=b.pageX,n=b.pageY;if(this.originalPosition){if(this.containment){if(b.pageX-this.offset.click.left<this.containment[0])g=this.containment[0]+this.offset.click.left;if(b.pageY-this.offset.click.top<this.containment[1])n=this.containment[1]+this.offset.click.top;if(b.pageX-this.offset.click.left>this.containment[2])g=this.containment[2]+this.offset.click.left;if(b.pageY-this.offset.click.top>this.containment[3])n=
76
+ this.containment[3]+this.offset.click.top}if(d.grid){n=this.originalPageY+Math.round((n-this.originalPageY)/d.grid[1])*d.grid[1];n=this.containment?!(n-this.offset.click.top<this.containment[1]||n-this.offset.click.top>this.containment[3])?n:!(n-this.offset.click.top<this.containment[1])?n-d.grid[1]:n+d.grid[1]:n;g=this.originalPageX+Math.round((g-this.originalPageX)/d.grid[0])*d.grid[0];g=this.containment?!(g-this.offset.click.left<this.containment[0]||g-this.offset.click.left>this.containment[2])?
77
+ g:!(g-this.offset.click.left<this.containment[0])?g-d.grid[0]:g+d.grid[0]:g}}return{top:n-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop()),left:g-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");
78
  this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(b,d,c){c=c||this._uiHash();a.ui.plugin.call(this,b,[d,c]);if(b=="drag")this.positionAbs=this._convertPositionTo("absolute");return a.widget.prototype._trigger.call(this,b,d,c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,absolutePosition:this.positionAbs,offset:this.positionAbs}}}));a.extend(a.ui.draggable,{version:"1.7.2",
79
  eventPrefix:"drag",defaults:{addClasses:true,appendTo:"parent",axis:false,cancel:":input,option",connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,delay:0,distance:1,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false}});a.ui.plugin.add("draggable","connectToSortable",{start:function(b,
80
+ d){var c=a(this).data("draggable"),e=c.options,g=a.extend({},d,{item:c.element});c.sortables=[];a(e.connectToSortable).each(function(){var n=a.data(this,"sortable");if(n&&!n.options.disabled){c.sortables.push({instance:n,shouldRevert:n.options.revert});n._refreshItems();n._trigger("activate",b,g)}})},stop:function(b,d){var c=a(this).data("draggable"),e=a.extend({},d,{item:c.element});a.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=
81
  false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(b);this.instance.options.helper=this.instance.options._helper;c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",b,e)}})},drag:function(b,d){var c=a(this).data("draggable"),e=this;a.each(c.sortables,function(){this.instance.positionAbs=c.positionAbs;this.instance.helperProportions=c.helperProportions;
82
  this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=a(e).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return d.helper[0]};b.target=this.instance.currentItem[0];this.instance._mouseCapture(b,true);this.instance._mouseStart(b,true,true);this.instance.offset.click.top=
83
  c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;c._trigger("toSortable",b);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(b)}else if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;
87
  document&&b.scrollParent[0].tagName!="HTML")b.overflowOffset=b.scrollParent.offset()},drag:function(b){var d=a(this).data("draggable"),c=d.options,e=false;if(d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!="x")if(d.overflowOffset.top+d.scrollParent[0].offsetHeight-b.pageY<c.scrollSensitivity)d.scrollParent[0].scrollTop=e=d.scrollParent[0].scrollTop+c.scrollSpeed;else if(b.pageY-d.overflowOffset.top<c.scrollSensitivity)d.scrollParent[0].scrollTop=e=d.scrollParent[0].scrollTop-
88
  c.scrollSpeed;if(!c.axis||c.axis!="y")if(d.overflowOffset.left+d.scrollParent[0].offsetWidth-b.pageX<c.scrollSensitivity)d.scrollParent[0].scrollLeft=e=d.scrollParent[0].scrollLeft+c.scrollSpeed;else if(b.pageX-d.overflowOffset.left<c.scrollSensitivity)d.scrollParent[0].scrollLeft=e=d.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(b.pageY-a(document).scrollTop()<c.scrollSensitivity)e=a(document).scrollTop(a(document).scrollTop()-c.scrollSpeed);else if(a(window).height()-
89
  (b.pageY-a(document).scrollTop())<c.scrollSensitivity)e=a(document).scrollTop(a(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(b.pageX-a(document).scrollLeft()<c.scrollSensitivity)e=a(document).scrollLeft(a(document).scrollLeft()-c.scrollSpeed);else if(a(window).width()-(b.pageX-a(document).scrollLeft())<c.scrollSensitivity)e=a(document).scrollLeft(a(document).scrollLeft()+c.scrollSpeed)}e!==false&&a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(d,b)}});a.ui.plugin.add("draggable",
90
+ "snap",{start:function(){var b=a(this).data("draggable"),d=b.options;b.snapElements=[];a(d.snap.constructor!=String?d.snap.items||":data(draggable)":d.snap).each(function(){var c=a(this),e=c.offset();this!=b.element[0]&&b.snapElements.push({item:this,width:c.outerWidth(),height:c.outerHeight(),top:e.top,left:e.left})})},drag:function(b,d){for(var c=a(this).data("draggable"),e=c.options,g=e.snapTolerance,n=d.offset.left,m=n+c.helperProportions.width,l=d.offset.top,f=l+c.helperProportions.height,h=
91
+ c.snapElements.length-1;h>=0;h--){var k=c.snapElements[h].left,o=k+c.snapElements[h].width,r=c.snapElements[h].top,q=r+c.snapElements[h].height;if(k-g<n&&n<o+g&&r-g<l&&l<q+g||k-g<n&&n<o+g&&r-g<f&&f<q+g||k-g<m&&m<o+g&&r-g<l&&l<q+g||k-g<m&&m<o+g&&r-g<f&&f<q+g){if(e.snapMode!="inner"){var p=Math.abs(r-f)<=g,t=Math.abs(q-l)<=g,v=Math.abs(k-m)<=g,i=Math.abs(o-n)<=g;if(p)d.position.top=c._convertPositionTo("relative",{top:r-c.helperProportions.height,left:0}).top-c.margins.top;if(t)d.position.top=c._convertPositionTo("relative",
92
+ {top:q,left:0}).top-c.margins.top;if(v)d.position.left=c._convertPositionTo("relative",{top:0,left:k-c.helperProportions.width}).left-c.margins.left;if(i)d.position.left=c._convertPositionTo("relative",{top:0,left:o}).left-c.margins.left}var j=p||t||v||i;if(e.snapMode!="outer"){p=Math.abs(r-l)<=g;t=Math.abs(q-f)<=g;v=Math.abs(k-n)<=g;i=Math.abs(o-m)<=g;if(p)d.position.top=c._convertPositionTo("relative",{top:r,left:0}).top-c.margins.top;if(t)d.position.top=c._convertPositionTo("relative",{top:q-c.helperProportions.height,
93
+ left:0}).top-c.margins.top;if(v)d.position.left=c._convertPositionTo("relative",{top:0,left:k}).left-c.margins.left;if(i)d.position.left=c._convertPositionTo("relative",{top:0,left:o-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[h].snapping&&(p||t||v||i||j))c.options.snap.snap&&c.options.snap.snap.call(c.element,b,a.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=p||t||v||i||j}else{c.snapElements[h].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,
94
+ b,a.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=false}}}});a.ui.plugin.add("draggable","stack",{start:function(){var b=a(this).data("draggable").options,d=a.makeArray(a(b.stack.group)).sort(function(c,e){return(parseInt(a(c).css("zIndex"),10)||b.stack.min)-(parseInt(a(e).css("zIndex"),10)||b.stack.min)});a(d).each(function(c){this.style.zIndex=b.stack.min+c});this[0].style.zIndex=b.stack.min+d.length}});a.ui.plugin.add("draggable","zIndex",{start:function(b,d){b=
95
  a(d.helper);d=a(this).data("draggable").options;if(b.css("zIndex"))d._zIndex=b.css("zIndex");b.css("zIndex",d.zIndex)},stop:function(b,d){b=a(this).data("draggable").options;b._zIndex&&a(d.helper).css("zIndex",b._zIndex)}})})(jQuery);(function(a){a.widget("ui.droppable",{_init:function(){var b=this.options,d=b.accept;this.isover=0;this.isout=1;this.options.accept=this.options.accept&&a.isFunction(this.options.accept)?this.options.accept:function(c){return c.is(d)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};a.ui.ddmanager.droppables[this.options.scope]=a.ui.ddmanager.droppables[this.options.scope]||[];a.ui.ddmanager.droppables[this.options.scope].push(this);this.options.addClasses&&
96
  this.element.addClass("ui-droppable")},destroy:function(){for(var b=a.ui.ddmanager.droppables[this.options.scope],d=0;d<b.length;d++)b[d]==this&&b.splice(d,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable")},_setData:function(b,d){if(b=="accept")this.options.accept=d&&a.isFunction(d)?d:function(c){return c.is(d)};else a.widget.prototype._setData.apply(this,arguments)},_activate:function(b){var d=a.ui.ddmanager.current;this.options.activeClass&&
97
  this.element.addClass(this.options.activeClass);d&&this._trigger("activate",b,this.ui(d))},_deactivate:function(b){var d=a.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);d&&this._trigger("deactivate",b,this.ui(d))},_over:function(b){var d=a.ui.ddmanager.current;if(!(!d||(d.currentItem||d.element)[0]==this.element[0]))if(this.options.accept.call(this.element[0],d.currentItem||d.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass);
98
+ this._trigger("over",b,this.ui(d))}},_out:function(b){var d=a.ui.ddmanager.current;if(!(!d||(d.currentItem||d.element)[0]==this.element[0]))if(this.options.accept.call(this.element[0],d.currentItem||d.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",b,this.ui(d))}},_drop:function(b,d){var c=d||a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var g=
99
+ a.data(this,"droppable");if(g.options.greedy&&a.ui.intersect(c,a.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.options.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop",b,this.ui(c));return this.element}return false},ui:function(b){return{draggable:b.currentItem||
100
+ b.element,helper:b.helper,position:b.position,absolutePosition:b.positionAbs,offset:b.positionAbs}}});a.extend(a.ui.droppable,{version:"1.7.2",eventPrefix:"drop",defaults:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"}});a.ui.intersect=function(b,d,c){if(!d.offset)return false;var e=(b.positionAbs||b.position.absolute).left,g=e+b.helperProportions.width,n=(b.positionAbs||b.position.absolute).top,m=n+b.helperProportions.height,l=d.offset.left,
101
+ f=l+d.proportions.width,h=d.offset.top,k=h+d.proportions.height;switch(c){case "fit":return l<e&&g<f&&h<n&&m<k;case "intersect":return l<e+b.helperProportions.width/2&&g-b.helperProportions.width/2<f&&h<n+b.helperProportions.height/2&&m-b.helperProportions.height/2<k;case "pointer":c=(b.positionAbs||b.position.absolute).left+(b.clickOffset||b.offset.click).left;b=(b.positionAbs||b.position.absolute).top+(b.clickOffset||b.offset.click).top;return d=a.ui.isOver(b,c,h,l,d.proportions.height,d.proportions.width);
102
+ case "touch":return(n>=h&&n<=k||m>=h&&m<=k||n<h&&m>k)&&(e>=l&&e<=f||g>=l&&g<=f||e<l&&g>f);default:return false}};a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,d){var c=a.ui.ddmanager.droppables[b.options.scope],e=d?d.type:null,g=(b.currentItem||b.element).find(":data(droppable)").andSelf(),n=0;a:for(;n<c.length;n++)if(!(c[n].options.disabled||b&&!c[n].options.accept.call(c[n].element[0],b.currentItem||b.element))){for(var m=0;m<g.length;m++)if(g[m]==c[n].element[0]){c[n].proportions.height=
103
+ 0;continue a}c[n].visible=c[n].element.css("display")!="none";if(c[n].visible){c[n].offset=c[n].element.offset();c[n].proportions={width:c[n].element[0].offsetWidth,height:c[n].element[0].offsetHeight};e=="mousedown"&&c[n]._activate.call(c[n],d)}}},drop:function(b,d){var c=false;a.each(a.ui.ddmanager.droppables[b.options.scope],function(){if(this.options){if(!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance))c=this._drop.call(this,d);if(!this.options.disabled&&this.visible&&
104
+ this.options.accept.call(this.element[0],b.currentItem||b.element)){this.isout=1;this.isover=0;this._deactivate.call(this,d)}}});return c},drag:function(b,d){b.options.refreshPositions&&a.ui.ddmanager.prepareOffsets(b,d);a.each(a.ui.ddmanager.droppables[b.options.scope],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=a.ui.intersect(b,this,this.options.tolerance);if(c=!c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");
105
+ if(g.length){e=a.data(g[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,d)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,d);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,d)}}}})}}})(jQuery);/*
106
  : Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
107
  */
108
+ (function(){var a=Date,b=a.prototype,d=[];function c(e,g){g||(g=2);return("000"+e).slice(g*-1)}a.normalizeFormat=function(e){d=[];(new Date).$format(e);return d.join("")};a.strftime=function(e,g){return(new Date(g*1000)).$format(e)};a.strtotime=function(e){e=a.parse(e);e.addMinutes(e.getTimezoneOffset()*-1);return Math.round(a.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds(),e.getUTCMilliseconds())/1000)};b.$format=function(e){var g=this,n;
109
+ function m(l){d.push(l);return g.toString(l)}return e?e.replace(/(%|\\)?.|%%/g,function(l){if(l.charAt(0)==="\\"||l.substring(0,2)==="%%")return l.replace("\\","").replace("%%","%");switch(l){case "d":case "%d":return m("dd");case "D":case "%a":return m("ddd");case "j":case "%e":return m("d");case "l":case "%A":return m("dddd");case "N":case "%u":return g.getDay()+1;case "S":return m("S");case "w":case "%w":return g.getDay();case "z":return g.getOrdinalNumber();case "%j":return c(g.getOrdinalNumber(),
110
+ 3);case "%U":l=g.clone().set({month:0,day:1}).addDays(-1).moveToDayOfWeek(0);var f=g.clone().addDays(1).moveToDayOfWeek(0,-1);return f<l?"00":c((f.getOrdinalNumber()-l.getOrdinalNumber())/7+1);case "W":case "%V":return g.getISOWeek();case "%W":return c(g.getWeek());case "F":case "%B":return m("MMMM");case "m":case "%m":return m("MM");case "M":case "%b":case "%h":return m("MMM");case "n":return m("M");case "t":return a.getDaysInMonth(g.getFullYear(),g.getMonth());case "L":return a.isLeapYear(g.getFullYear())?
111
+ 1:0;case "o":case "%G":return g.setWeek(g.getISOWeek()).toString("yyyy");case "%g":return g.$format("%G").slice(-2);case "Y":case "%Y":return m("yyyy");case "y":case "%y":return m("yy");case "a":case "%p":return m("tt").toLowerCase();case "A":return m("tt").toUpperCase();case "g":case "%I":return m("h");case "G":return m("H");case "h":return m("hh");case "H":case "%H":return m("HH");case "i":case "%M":return m("mm");case "s":case "%S":return m("ss");case "u":return c(g.getMilliseconds(),3);case "I":return g.isDaylightSavingTime()?
112
+ 1:0;case "O":return g.getUTCOffset();case "P":n=g.getUTCOffset();return n.substring(0,n.length-2)+":"+n.substring(n.length-2);case "e":case "T":case "%z":case "%Z":return g.getTimezone();case "Z":return g.getTimezoneOffset()*-60;case "B":l=new Date;return Math.floor((l.getHours()*3600+l.getMinutes()*60+l.getSeconds()+(l.getTimezoneOffset()+60)*60)/86.4);case "c":return g.toISOString().replace(/\"/g,"");case "U":return a.strtotime("now");case "%c":return m("d")+" "+m("t");case "%C":return Math.floor(g.getFullYear()/
113
+ 100+1);case "%D":return m("MM/dd/yy");case "%n":return"\\n";case "%t":return"\\t";case "%r":return m("hh:mm tt");case "%R":return m("H:mm");case "%T":return m("H:mm:ss");case "%x":return m("d");case "%X":return m("t");default:d.push(l);return l}}):this._toString()};if(!b.format)b.format=b.$format})();
lib/languages/date-pt-BR.js ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Version: 1.0 Alpha-1
3
+ * Build Date: 13-Nov-2007
4
+ * Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved.
5
+ * License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
6
+ * Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
7
+ */
8
+ Date.CultureInfo={name:"pt-BR",englishName:"Portuguese (Brazil)",nativeName:"Português (Brasil)",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"],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"],amDesignator:"",pmDesignator:"",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"dmy",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"},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:/^(\+|after|from)/i,subtract:/^(\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/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)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
9
+ Date.getMonthNumberFromName=function(name){var n=Date.CultureInfo.monthNames,m=Date.CultureInfo.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
10
+ return-1;};Date.getDayNumberFromName=function(name){var n=Date.CultureInfo.dayNames,m=Date.CultureInfo.abbreviatedDayNames,o=Date.CultureInfo.shortestDayNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
11
+ return-1;};Date.isLeapYear=function(year){return(((year%4===0)&&(year%100!==0))||(year%400===0));};Date.getDaysInMonth=function(year,month){return[31,(Date.isLeapYear(year)?29:28),31,30,31,30,31,31,30,31,30,31][month];};Date.getTimezoneOffset=function(s,dst){return(dst||false)?Date.CultureInfo.abbreviatedTimeZoneDST[s.toUpperCase()]:Date.CultureInfo.abbreviatedTimeZoneStandard[s.toUpperCase()];};Date.getTimezoneAbbreviation=function(offset,dst){var n=(dst||false)?Date.CultureInfo.abbreviatedTimeZoneDST:Date.CultureInfo.abbreviatedTimeZoneStandard,p;for(p in n){if(n[p]===offset){return p;}}
12
+ return null;};Date.prototype.clone=function(){return new Date(this.getTime());};Date.prototype.compareTo=function(date){if(isNaN(this)){throw new Error(this);}
13
+ if(date instanceof Date&&!isNaN(date)){return(this>date)?1:(this<date)?-1:0;}else{throw new TypeError(date);}};Date.prototype.equals=function(date){return(this.compareTo(date)===0);};Date.prototype.between=function(start,end){var t=this.getTime();return t>=start.getTime()&&t<=end.getTime();};Date.prototype.addMilliseconds=function(value){this.setMilliseconds(this.getMilliseconds()+value);return this;};Date.prototype.addSeconds=function(value){return this.addMilliseconds(value*1000);};Date.prototype.addMinutes=function(value){return this.addMilliseconds(value*60000);};Date.prototype.addHours=function(value){return this.addMilliseconds(value*3600000);};Date.prototype.addDays=function(value){return this.addMilliseconds(value*86400000);};Date.prototype.addWeeks=function(value){return this.addMilliseconds(value*604800000);};Date.prototype.addMonths=function(value){var n=this.getDate();this.setDate(1);this.setMonth(this.getMonth()+value);this.setDate(Math.min(n,this.getDaysInMonth()));return this;};Date.prototype.addYears=function(value){return this.addMonths(value*12);};Date.prototype.add=function(config){if(typeof config=="number"){this._orient=config;return this;}
14
+ var x=config;if(x.millisecond||x.milliseconds){this.addMilliseconds(x.millisecond||x.milliseconds);}
15
+ if(x.second||x.seconds){this.addSeconds(x.second||x.seconds);}
16
+ if(x.minute||x.minutes){this.addMinutes(x.minute||x.minutes);}
17
+ if(x.hour||x.hours){this.addHours(x.hour||x.hours);}
18
+ if(x.month||x.months){this.addMonths(x.month||x.months);}
19
+ if(x.year||x.years){this.addYears(x.year||x.years);}
20
+ if(x.day||x.days){this.addDays(x.day||x.days);}
21
+ return this;};Date._validate=function(value,min,max,name){if(typeof value!="number"){throw new TypeError(value+" is not a Number.");}else if(value<min||value>max){throw new RangeError(value+" is not a valid value for "+name+".");}
22
+ return true;};Date.validateMillisecond=function(n){return Date._validate(n,0,999,"milliseconds");};Date.validateSecond=function(n){return Date._validate(n,0,59,"seconds");};Date.validateMinute=function(n){return Date._validate(n,0,59,"minutes");};Date.validateHour=function(n){return Date._validate(n,0,23,"hours");};Date.validateDay=function(n,year,month){return Date._validate(n,1,Date.getDaysInMonth(year,month),"days");};Date.validateMonth=function(n){return Date._validate(n,0,11,"months");};Date.validateYear=function(n){return Date._validate(n,1,9999,"seconds");};Date.prototype.set=function(config){var x=config;if(!x.millisecond&&x.millisecond!==0){x.millisecond=-1;}
23
+ if(!x.second&&x.second!==0){x.second=-1;}
24
+ if(!x.minute&&x.minute!==0){x.minute=-1;}
25
+ if(!x.hour&&x.hour!==0){x.hour=-1;}
26
+ if(!x.day&&x.day!==0){x.day=-1;}
27
+ if(!x.month&&x.month!==0){x.month=-1;}
28
+ if(!x.year&&x.year!==0){x.year=-1;}
29
+ if(x.millisecond!=-1&&Date.validateMillisecond(x.millisecond)){this.addMilliseconds(x.millisecond-this.getMilliseconds());}
30
+ if(x.second!=-1&&Date.validateSecond(x.second)){this.addSeconds(x.second-this.getSeconds());}
31
+ if(x.minute!=-1&&Date.validateMinute(x.minute)){this.addMinutes(x.minute-this.getMinutes());}
32
+ if(x.hour!=-1&&Date.validateHour(x.hour)){this.addHours(x.hour-this.getHours());}
33
+ if(x.month!==-1&&Date.validateMonth(x.month)){this.addMonths(x.month-this.getMonth());}
34
+ if(x.year!=-1&&Date.validateYear(x.year)){this.addYears(x.year-this.getFullYear());}
35
+ if(x.day!=-1&&Date.validateDay(x.day,this.getFullYear(),this.getMonth())){this.addDays(x.day-this.getDate());}
36
+ if(x.timezone){this.setTimezone(x.timezone);}
37
+ if(x.timezoneOffset){this.setTimezoneOffset(x.timezoneOffset);}
38
+ return this;};Date.prototype.clearTime=function(){this.setHours(0);this.setMinutes(0);this.setSeconds(0);this.setMilliseconds(0);return this;};Date.prototype.isLeapYear=function(){var y=this.getFullYear();return(((y%4===0)&&(y%100!==0))||(y%400===0));};Date.prototype.isWeekday=function(){return!(this.is().sat()||this.is().sun());};Date.prototype.getDaysInMonth=function(){return Date.getDaysInMonth(this.getFullYear(),this.getMonth());};Date.prototype.moveToFirstDayOfMonth=function(){return this.set({day:1});};Date.prototype.moveToLastDayOfMonth=function(){return this.set({day:this.getDaysInMonth()});};Date.prototype.moveToDayOfWeek=function(day,orient){var diff=(day-this.getDay()+7*(orient||+1))%7;return this.addDays((diff===0)?diff+=7*(orient||+1):diff);};Date.prototype.moveToMonth=function(month,orient){var diff=(month-this.getMonth()+12*(orient||+1))%12;return this.addMonths((diff===0)?diff+=12*(orient||+1):diff);};Date.prototype.getDayOfYear=function(){return Math.floor((this-new Date(this.getFullYear(),0,1))/86400000);};Date.prototype.getWeekOfYear=function(firstDayOfWeek){var y=this.getFullYear(),m=this.getMonth(),d=this.getDate();var dow=firstDayOfWeek||Date.CultureInfo.firstDayOfWeek;var offset=7+1-new Date(y,0,1).getDay();if(offset==8){offset=1;}
39
+ var daynum=((Date.UTC(y,m,d,0,0,0)-Date.UTC(y,0,1,0,0,0))/86400000)+1;var w=Math.floor((daynum-offset+7)/7);if(w===dow){y--;var prevOffset=7+1-new Date(y,0,1).getDay();if(prevOffset==2||prevOffset==8){w=53;}else{w=52;}}
40
+ return w;};Date.prototype.isDST=function(){console.log('isDST');return this.toString().match(/(E|C|M|P)(S|D)T/)[2]=="D";};Date.prototype.getTimezone=function(){return Date.getTimezoneAbbreviation(this.getUTCOffset,this.isDST());};Date.prototype.setTimezoneOffset=function(s){var here=this.getTimezoneOffset(),there=Number(s)*-6/10;this.addMinutes(there-here);return this;};Date.prototype.setTimezone=function(s){return this.setTimezoneOffset(Date.getTimezoneOffset(s));};Date.prototype.getUTCOffset=function(){var n=this.getTimezoneOffset()*-10/6,r;if(n<0){r=(n-10000).toString();return r[0]+r.substr(2);}else{r=(n+10000).toString();return"+"+r.substr(1);}};Date.prototype.getDayName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedDayNames[this.getDay()]:Date.CultureInfo.dayNames[this.getDay()];};Date.prototype.getMonthName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedMonthNames[this.getMonth()]:Date.CultureInfo.monthNames[this.getMonth()];};Date.prototype._toString=Date.prototype.toString;Date.prototype.toString=function(format){var self=this;var p=function p(s){return(s.toString().length==1)?"0"+s:s;};return format?format.replace(/dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?/g,function(format){switch(format){case"hh":return p(self.getHours()<13?self.getHours():(self.getHours()-12));case"h":return self.getHours()<13?self.getHours():(self.getHours()-12);case"HH":return p(self.getHours());case"H":return self.getHours();case"mm":return p(self.getMinutes());case"m":return self.getMinutes();case"ss":return p(self.getSeconds());case"s":return self.getSeconds();case"yyyy":return self.getFullYear();case"yy":return self.getFullYear().toString().substring(2,4);case"dddd":return self.getDayName();case"ddd":return self.getDayName(true);case"dd":return p(self.getDate());case"d":return self.getDate().toString();case"MMMM":return self.getMonthName();case"MMM":return self.getMonthName(true);case"MM":return p((self.getMonth()+1));case"M":return self.getMonth()+1;case"t":return self.getHours()<12?Date.CultureInfo.amDesignator.substring(0,1):Date.CultureInfo.pmDesignator.substring(0,1);case"tt":return self.getHours()<12?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator;case"zzz":case"zz":case"z":return"";}}):this._toString();};
41
+ Date.now=function(){return new Date();};Date.today=function(){return Date.now().clearTime();};Date.prototype._orient=+1;Date.prototype.next=function(){this._orient=+1;return this;};Date.prototype.last=Date.prototype.prev=Date.prototype.previous=function(){this._orient=-1;return this;};Date.prototype._is=false;Date.prototype.is=function(){this._is=true;return this;};Number.prototype._dateElement="day";Number.prototype.fromNow=function(){var c={};c[this._dateElement]=this;return Date.now().add(c);};Number.prototype.ago=function(){var c={};c[this._dateElement]=this*-1;return Date.now().add(c);};(function(){var $D=Date.prototype,$N=Number.prototype;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/),de;var df=function(n){return function(){if(this._is){this._is=false;return this.getDay()==n;}
42
+ return this.moveToDayOfWeek(n,this._orient);};};for(var i=0;i<dx.length;i++){$D[dx[i]]=$D[dx[i].substring(0,3)]=df(i);}
43
+ var mf=function(n){return function(){if(this._is){this._is=false;return this.getMonth()===n;}
44
+ return this.moveToMonth(n,this._orient);};};for(var j=0;j<mx.length;j++){$D[mx[j]]=$D[mx[j].substring(0,3)]=mf(j);}
45
+ var ef=function(j){return function(){if(j.substring(j.length-1)!="s"){j+="s";}
46
+ 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();$D[de]=$D[de+"s"]=ef(px[k]);$N[de]=$N[de+"s"]=nf(de);}}());Date.prototype.toJSONString=function(){return this.toString("yyyy-MM-ddThh:mm:ssZ");};Date.prototype.toShortDateString=function(){return this.toString(Date.CultureInfo.formatPatterns.shortDatePattern);};Date.prototype.toLongDateString=function(){return this.toString(Date.CultureInfo.formatPatterns.longDatePattern);};Date.prototype.toShortTimeString=function(){return this.toString(Date.CultureInfo.formatPatterns.shortTimePattern);};Date.prototype.toLongTimeString=function(){return this.toString(Date.CultureInfo.formatPatterns.longTimePattern);};Date.prototype.getOrdinal=function(){switch(this.getDate()){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th";}};
47
+ (function(){Date.Parsing={Exception:function(s){this.message="Parse error at '"+s.substring(0,10)+" ...'";}};var $P=Date.Parsing;var _=$P.Operators={rtoken:function(r){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){return function(s){return _.rtoken(new RegExp("^\s*"+s+"\s*"))(s);};},stoken:function(s){return _.rtoken(new RegExp("^"+s));},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;}
48
+ break;}
49
+ 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];}
50
+ rx.push(r[0]);s=r[1];}
51
+ return[rx,s];};},optional:function(p){return function(s){var r=null;try{r=p.call(this,s);}catch(e){return[null,s];}
52
+ return[r[0],r[1]];};},not:function(p){return function(s){try{p.call(this,s);}catch(e){return[null,s];}
53
+ 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));}
54
+ 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;}
55
+ if(r instanceof $P.Exception){throw r;}else{return r;}};},any:function(){var px=arguments;return function(s){var r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
56
+ try{r=(px[i].call(this,s));}catch(e){r=null;}
57
+ if(r){return r;}}
58
+ 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;}
59
+ try{r=(px[i].call(this,s));}catch(e){throw new $P.Exception(s);}
60
+ rx.push(r[0]);s=r[1];}
61
+ return[rx,s];};},all:function(){var px=arguments,_=_;return _.each(_.optional(px));},sequence:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;if(px.length==1){return px[0];}
62
+ 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;}
63
+ rx.push(r[0]);try{q=d.call(this,r[1]);}catch(ex){q=null;break;}
64
+ s=q[1];}
65
+ if(!r){throw new $P.Exception(s);}
66
+ if(q){throw new $P.Exception(q[1]);}
67
+ if(c){try{r=c.call(this,r[1]);}catch(ey){throw new $P.Exception(r[1]);}}
68
+ return[rx,(r?r[1]:s)];};},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){var r=null,p=null,q=null,rx=null,best=[[],s],last=false;for(var i=0;i<px.length;i++){q=null;p=null;r=null;last=(px.length==1);try{r=px[i].call(this,s);}catch(e){continue;}
69
+ rx=[[r[0]],r[1]];if(r[1].length>0&&!last){try{q=d.call(this,r[1]);}catch(ex){last=true;}}else{last=true;}
70
+ if(!last&&q[1].length===0){last=true;}
71
+ if(!last){var qx=[];for(var j=0;j<px.length;j++){if(i!=j){qx.push(px[j]);}}
72
+ p=_.set(qx,d).call(this,q[1]);if(p[0].length>0){rx[0]=rx[0].concat(p[0]);rx[1]=p[1];}}
73
+ if(rx[1].length<best[1].length){best=rx;}
74
+ if(best[1].length===0){break;}}
75
+ if(best[0].length===0){return best;}
76
+ if(c){try{q=c.call(this,best[1]);}catch(ey){throw new $P.Exception(best[1]);}
77
+ best[1]=q[1];}
78
+ return best;};},forward:function(gr,fname){return function(s){return gr[fname].call(this,s);};},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);}
79
+ return rx;};}};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];}
80
+ 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]]);}
81
+ 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 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]);}}}
82
+ return rx;};Date.Grammar={};Date.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)?Date.getMonthNumberFromName(s):(Number(s)-1));};},year:function(s){return function(){var n=Number(s);this.year=((s.length>2)?n:(n+(((n+2000)<Date.CultureInfo.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];var now=new Date();this.year=now.getFullYear();this.month=now.getMonth();this.day=1;this.hour=0;this.minute=0;this.second=0;for(var i=0;i<x.length;i++){if(x[i]){x[i].call(this);}}
83
+ this.hour=(this.meridian=="p"&&this.hour<13)?this.hour+12:this.hour;if(this.day>Date.getDaysInMonth(this.year,this.month)){throw new RangeError(this.day+" is not a valid value for days.");}
84
+ 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});}
85
+ return r;},finish:function(x){x=(x instanceof Array)?flattenAndCompact(x):[x];if(x.length===0){return null;}
86
+ for(var i=0;i<x.length;i++){if(typeof x[i]=="function"){x[i].call(this);}}
87
+ if(this.now){return new Date();}
88
+ var today=Date.today();var method=null;var expression=!!(this.days!=null||this.orient||this.operator);if(expression){var gap,mod,orient;orient=((this.orient=="past"||this.operator=="subtract")?-1:1);if(this.weekday){this.unit="day";gap=(Date.getDayNumberFromName(this.weekday)-today.getDay());mod=7;this.days=gap?((gap+(orient*mod))%mod):(orient*mod);}
89
+ if(this.month){this.unit="month";gap=(this.month-today.getMonth());mod=12;this.months=gap?((gap+(orient*mod))%mod):(orient*mod);this.month=null;}
90
+ if(!this.unit){this.unit="day";}
91
+ if(this[this.unit+"s"]==null||this.operator!=null){if(!this.value){this.value=1;}
92
+ if(this.unit=="week"){this.unit="day";this.value=this.value*7;}
93
+ this[this.unit+"s"]=this.value*orient;}
94
+ return today.add(this);}else{if(this.meridian&&this.hour){this.hour=(this.hour<13&&this.meridian=="p")?this.hour+12:this.hour;}
95
+ if(this.weekday&&!this.day){this.day=(today.addDays((Date.getDayNumberFromName(this.weekday)-today.getDay()))).getDate();}
96
+ if(this.month&&!this.day){this.day=1;}
97
+ return today.set(this);}}};var _=Date.Parsing.Operators,g=Date.Grammar,t=Date.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=Date.CultureInfo.regexPatterns;var kx=keys.split(/\s+/),px=[];for(var i=0;i<kx.length;i++){px.push(_.replace(_.rtoken(c[kx[i]]),kx[i]));}
98
+ fn=_C[keys]=_.any.apply(null,px);}
99
+ return fn;};g.ctoken2=function(key){return _.rtoken(Date.CultureInfo.regexPatterns[key]);};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.mm,g.ss],g.timePartDelimiter));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?/),t.timezone));g.zz=_.cache(_.process(_.rtoken(/^(\+|\-)\s*\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);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));_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);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("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]);_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[Date.CultureInfo.dateElementOrder]||g.mdy).call(this,s));};g.format=_.process(_.many(_.any(_.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 Date.Parsing.Exception(fmt);}}),_.process(_.rtoken(/^[^dMyhHmstz]+/),function(s){return _.ignore(_.stoken(s));}))),function(rules){return _.process(_.each.apply(null,rules),t.finishExact);});var _F={};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]));}
100
+ return _.any.apply(null,rx);}else{return _get(fx);}};g._formats=g.formats(["yyyy-MM-ddTHH:mm:ss","ddd, MMM dd, yyyy H:mm:ss tt","ddd MMM d yyyy HH:mm:ss zzz","d"]);g._start=_.process(_.set([g.date,g.time,g.expression],g.generalDelimiter,g.whiteSpace),t.finish);g.start=function(s){try{var r=g._formats.call({},s);if(r[1].length===0){return r;}}catch(e){}
101
+ return g._start.call({},s);};}());Date._parse=Date.parse;Date.parse=function(s){var r=null;if(!s){return null;}
102
+ try{r=Date.Grammar.start.call({},s);}catch(e){return null;}
103
+ return((r[1].length===0)?r[0]:null);};Date.getParseFunction=function(fx){var fn=Date.Grammar.formats(fx);return function(s){var r=null;try{r=fn.call({},s);}catch(e){return null;}
104
+ return((r[1].length===0)?r[0]:null);};};Date.parseExact=function(s,fx){return Date.getParseFunction(fx)(s);};
lib/lib.txt CHANGED
@@ -35,6 +35,11 @@ We use this library for faster JSON parsing.
35
  http://www.json.org/js.html
36
  It is available under the public domain.
37
 
 
 
 
 
 
38
  tools.scrollable-1.1.2.js
39
  tools.scrollable.mousewheel-1.0.1.js
40
  The scrollable library supports the mouse wheel scrolling and manages the calendar's vertical scrolling.
35
  http://www.json.org/js.html
36
  It is available under the public domain.
37
 
38
+ sprintf-0.7-beta1.js
39
+ This libraries helps us to PHP style string substitution for localization.
40
+ http://www.diveintojavascript.com/projects/javascript-sprintf
41
+ BSD license
42
+
43
  tools.scrollable-1.1.2.js
44
  tools.scrollable.mousewheel-1.0.1.js
45
  The scrollable library supports the mouse wheel scrolling and manages the calendar's vertical scrolling.
lib/qunit.css CHANGED
@@ -1,119 +1,196 @@
 
1
 
2
- ol#qunit-tests {
3
- font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
4
- margin:0;
5
- padding:0;
6
- list-style-position:inside;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
- font-size: smaller;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  }
10
- ol#qunit-tests li{
11
- padding:0.4em 0.5em 0.4em 2.5em;
12
- border-bottom:1px solid #fff;
13
- font-size:small;
14
- list-style-position:inside;
15
  }
16
- ol#qunit-tests li ol{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  box-shadow: inset 0px 2px 13px #999;
18
  -moz-box-shadow: inset 0px 2px 13px #999;
19
  -webkit-box-shadow: inset 0px 2px 13px #999;
20
- margin-top:0.5em;
21
- margin-left:0;
22
- padding:0.5em;
23
- background-color:#fff;
24
- border-radius:15px;
25
- -moz-border-radius: 15px;
26
- -webkit-border-radius: 15px;
27
  }
28
- ol#qunit-tests li li{
29
- border-bottom:none;
30
- margin:0.5em;
31
- background-color:#fff;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  list-style-position: inside;
33
- padding:0.4em 0.5em 0.4em 0.5em;
34
- }
35
-
36
- ol#qunit-tests li li.pass{
37
- border-left:26px solid #C6E746;
38
- background-color:#fff;
39
- color:#5E740B;
40
- }
41
- ol#qunit-tests li li.fail{
42
- border-left:26px solid #EE5757;
43
- background-color:#fff;
44
- color:#710909;
45
- }
46
- ol#qunit-tests li.pass{
47
- background-color:#D2E0E6;
48
- color:#528CE0;
49
- }
50
- ol#qunit-tests li.fail{
51
- background-color:#EE5757;
52
- color:#000;
53
- }
54
- ol#qunit-tests li strong {
55
- cursor:pointer;
56
- }
57
- h1#qunit-header{
58
- background-color:#0d3349;
59
- margin:0;
60
- padding:0.5em 0 0.5em 1em;
61
- color:#fff;
62
- font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
63
- border-top-right-radius:15px;
64
- border-top-left-radius:15px;
65
- -moz-border-radius-topright:15px;
66
- -moz-border-radius-topleft:15px;
67
- -webkit-border-top-right-radius:15px;
68
- -webkit-border-top-left-radius:15px;
69
- text-shadow: rgba(0, 0, 0, 0.5) 4px 4px 1px;
70
- }
71
- h2#qunit-banner{
72
- font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
73
- height:5px;
74
- margin:0;
75
- padding:0;
76
- }
77
- h2#qunit-banner.qunit-pass{
78
- background-color:#C6E746;
79
- }
80
- h2#qunit-banner.qunit-fail, #qunit-testrunner-toolbar {
81
- background-color:#EE5757;
82
  }
83
- #qunit-testrunner-toolbar {
84
- font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
85
- padding:0;
86
- /*width:80%;*/
87
- padding:0em 0 0.5em 2em;
88
- font-size: small;
89
- }
90
- h2#qunit-userAgent {
91
- font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
92
- background-color:#2b81af;
93
- margin:0;
94
- padding:0;
95
- color:#fff;
96
- font-size: small;
97
- padding:0.5em 0 0.5em 2.5em;
98
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  }
100
- p#qunit-testresult{
101
- font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
102
- margin:0;
103
- font-size: small;
104
- color:#2b81af;
105
- border-bottom-right-radius:15px;
106
- border-bottom-left-radius:15px;
107
- -moz-border-radius-bottomright:15px;
108
- -moz-border-radius-bottomleft:15px;
109
- -webkit-border-bottom-right-radius:15px;
110
- -webkit-border-bottom-left-radius:15px;
111
- background-color:#D2E0E6;
112
- padding:0.5em 0.5em 0.5em 2.5em;
113
- }
114
- strong b.fail{
115
- color:#710909;
116
- }
117
- strong b.pass{
118
- color:#5E740B;
119
- }
1
+ /** Font Family and Sizes */
2
 
3
+ #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
4
+ font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
5
+ }
6
+
7
+ #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
8
+ #qunit-tests { font-size: smaller; }
9
+
10
+
11
+ /** Resets */
12
+
13
+ #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
14
+ margin: 0;
15
+ padding: 0;
16
+ }
17
+
18
+
19
+ /** Header */
20
+
21
+ #qunit-header {
22
+ padding: 0.5em 0 0.5em 1em;
23
+
24
+ color: #8699a4;
25
+ background-color: #0d3349;
26
+
27
+ font-size: 1.5em;
28
+ line-height: 1em;
29
+ font-weight: normal;
30
+
31
+ border-radius: 15px 15px 0 0;
32
+ -moz-border-radius: 15px 15px 0 0;
33
+ -webkit-border-top-right-radius: 15px;
34
+ -webkit-border-top-left-radius: 15px;
35
+ }
36
+
37
+ #qunit-header a {
38
+ text-decoration: none;
39
+ color: #c2ccd1;
40
+ }
41
+
42
+ #qunit-header a:hover,
43
+ #qunit-header a:focus {
44
+ color: #fff;
45
+ }
46
+
47
+ #qunit-banner {
48
+ height: 5px;
49
+ }
50
 
51
+ #qunit-testrunner-toolbar {
52
+ padding: 0em 0 0.5em 2em;
53
+ }
54
+
55
+ #qunit-userAgent {
56
+ padding: 0.5em 0 0.5em 2.5em;
57
+ background-color: #2b81af;
58
+ color: #fff;
59
+ text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
60
+ }
61
+
62
+
63
+ /** Tests: Pass/Fail */
64
+
65
+ #qunit-tests {
66
+ list-style-position: inside;
67
  }
68
+
69
+ #qunit-tests li {
70
+ padding: 0.4em 0.5em 0.4em 2.5em;
71
+ border-bottom: 1px solid #fff;
72
+ list-style-position: inside;
73
  }
74
+
75
+ #qunit-tests li strong {
76
+ cursor: pointer;
77
+ }
78
+
79
+ #qunit-tests ol {
80
+ margin-top: 0.5em;
81
+ padding: 0.5em;
82
+
83
+ background-color: #fff;
84
+
85
+ border-radius: 15px;
86
+ -moz-border-radius: 15px;
87
+ -webkit-border-radius: 15px;
88
+
89
  box-shadow: inset 0px 2px 13px #999;
90
  -moz-box-shadow: inset 0px 2px 13px #999;
91
  -webkit-box-shadow: inset 0px 2px 13px #999;
 
 
 
 
 
 
 
92
  }
93
+
94
+ #qunit-tests table {
95
+ border-collapse: collapse;
96
+ margin-top: .2em;
97
+ }
98
+
99
+ #qunit-tests th {
100
+ text-align: right;
101
+ vertical-align: top;
102
+ padding: 0 .5em 0 0;
103
+ }
104
+
105
+ #qunit-tests td {
106
+ vertical-align: top;
107
+ }
108
+
109
+ #qunit-tests pre {
110
+ margin: 0;
111
+ white-space: pre-wrap;
112
+ word-wrap: break-word;
113
+ }
114
+
115
+ #qunit-tests del {
116
+ background-color: #e0f2be;
117
+ color: #374e0c;
118
+ text-decoration: none;
119
+ }
120
+
121
+ #qunit-tests ins {
122
+ background-color: #ffcaca;
123
+ color: #500;
124
+ text-decoration: none;
125
+ }
126
+
127
+ /*** Test Counts */
128
+
129
+ #qunit-tests b.counts { color: black; }
130
+ #qunit-tests b.passed { color: #5E740B; }
131
+ #qunit-tests b.failed { color: #710909; }
132
+
133
+ #qunit-tests li li {
134
+ margin: 0.5em;
135
+ padding: 0.4em 0.5em 0.4em 0.5em;
136
+ background-color: #fff;
137
+ border-bottom: none;
138
  list-style-position: inside;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  }
140
+
141
+ /*** Passing Styles */
142
+
143
+ #qunit-tests li li.pass {
144
+ color: #5E740B;
145
+ background-color: #fff;
146
+ border-left: 26px solid #C6E746;
147
+ }
148
+
149
+ #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
150
+ #qunit-tests .pass .test-name { color: #366097; }
151
+
152
+ #qunit-tests .pass .test-actual,
153
+ #qunit-tests .pass .test-expected { color: #999999; }
154
+
155
+ #qunit-banner.qunit-pass { background-color: #C6E746; }
156
+
157
+ /*** Failing Styles */
158
+
159
+ #qunit-tests li li.fail {
160
+ color: #710909;
161
+ background-color: #fff;
162
+ border-left: 26px solid #EE5757;
163
+ }
164
+
165
+ #qunit-tests .fail { color: #000000; background-color: #EE5757; }
166
+ #qunit-tests .fail .test-name,
167
+ #qunit-tests .fail .module-name { color: #000000; }
168
+
169
+ #qunit-tests .fail .test-actual { color: #EE5757; }
170
+ #qunit-tests .fail .test-expected { color: green; }
171
+
172
+ #qunit-banner.qunit-fail,
173
+ #qunit-testrunner-toolbar { background-color: #EE5757; }
174
+
175
+
176
+ /** Footer */
177
+
178
+ #qunit-testresult {
179
+ padding: 0.5em 0.5em 0.5em 2.5em;
180
+
181
+ color: #2b81af;
182
+ background-color: #D2E0E6;
183
+
184
+ border-radius: 0 0 15px 15px;
185
+ -moz-border-radius: 0 0 15px 15px;
186
+ -webkit-border-bottom-right-radius: 15px;
187
+ -webkit-border-bottom-left-radius: 15px;
188
+ }
189
+
190
+ /** Fixture */
191
+
192
+ #qunit-fixture {
193
+ position: absolute;
194
+ top: -10000px;
195
+ left: -10000px;
196
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/qunit.js CHANGED
@@ -10,54 +10,234 @@
10
 
11
  (function(window) {
12
 
13
- var QUnit = {
 
 
 
 
 
 
 
 
 
14
 
15
- // Initialize the configuration options
16
- init: function() {
17
- config = {
18
- stats: { all: 0, bad: 0 },
19
- moduleStats: { all: 0, bad: 0 },
20
- started: +new Date,
21
- updateRate: 1000,
22
- blocking: false,
23
- autorun: false,
24
- assertions: [],
25
- filters: [],
26
- queue: []
27
- };
28
 
29
- var tests = id("qunit-tests"),
30
- banner = id("qunit-banner"),
31
- result = id("qunit-testresult");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
- if ( tests ) {
34
- tests.innerHTML = "";
 
 
 
 
 
35
  }
36
 
37
- if ( banner ) {
38
- banner.className = "";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  }
40
 
41
- if ( result ) {
42
- result.parentNode.removeChild( result );
 
 
 
 
 
 
 
 
 
 
 
43
  }
44
  },
45
-
46
- // call on start of module test to prepend name to all tests
47
- module: function(name, testEnvironment) {
48
- config.currentModule = name;
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
- synchronize(function() {
51
- if ( config.currentModule ) {
52
- QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  }
54
 
55
- config.currentModule = name;
56
- config.moduleTestEnvironment = testEnvironment;
57
- config.moduleStats = { all: 0, bad: 0 };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
- QUnit.moduleStart( name, testEnvironment );
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  },
62
 
63
  asyncTest: function(testName, expected, callback) {
@@ -70,7 +250,7 @@ var QUnit = {
70
  },
71
 
72
  test: function(testName, expected, callback, async) {
73
- var name = testName, testEnvironment, testEnvironmentArg;
74
 
75
  if ( arguments.length === 2 ) {
76
  callback = expected;
@@ -83,178 +263,25 @@ var QUnit = {
83
  }
84
 
85
  if ( config.currentModule ) {
86
- name = config.currentModule + " module: " + name;
87
  }
88
 
89
- if ( !validTest(name) ) {
90
  return;
91
  }
92
-
93
- synchronize(function() {
94
- QUnit.testStart( testName );
95
-
96
- testEnvironment = extend({
97
- setup: function() {},
98
- teardown: function() {}
99
- }, config.moduleTestEnvironment);
100
- if (testEnvironmentArg) {
101
- extend(testEnvironment,testEnvironmentArg);
102
- }
103
-
104
- // allow utility functions to access the current test environment
105
- QUnit.current_testEnvironment = testEnvironment;
106
-
107
- config.assertions = [];
108
- config.expected = expected;
109
-
110
- try {
111
- if ( !config.pollution ) {
112
- saveGlobal();
113
- }
114
-
115
- testEnvironment.setup.call(testEnvironment);
116
- } catch(e) {
117
- QUnit.ok( false, "Setup failed on " + name + ": " + e.message );
118
- }
119
-
120
- if ( async ) {
121
- QUnit.stop();
122
- }
123
-
124
- try {
125
- callback.call(testEnvironment);
126
- } catch(e) {
127
- fail("Test " + name + " died, exception and test follows", e, callback);
128
- QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message );
129
- // else next test will carry the responsibility
130
- saveGlobal();
131
-
132
- // Restart the tests if they're blocking
133
- if ( config.blocking ) {
134
- start();
135
- }
136
- }
137
- });
138
-
139
- synchronize(function() {
140
- try {
141
- checkPollution();
142
- testEnvironment.teardown.call(testEnvironment);
143
- } catch(e) {
144
- QUnit.ok( false, "Teardown failed on " + name + ": " + e.message );
145
- }
146
-
147
- try {
148
- QUnit.reset();
149
- } catch(e) {
150
- fail("reset() failed, following Test " + name + ", exception and reset fn follows", e, reset);
151
- }
152
-
153
- if ( config.expected && config.expected != config.assertions.length ) {
154
- QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" );
155
- }
156
-
157
- var good = 0, bad = 0,
158
- tests = id("qunit-tests");
159
-
160
- config.stats.all += config.assertions.length;
161
- config.moduleStats.all += config.assertions.length;
162
-
163
- if ( tests ) {
164
- var ol = document.createElement("ol");
165
- ol.style.display = "none";
166
-
167
- for ( var i = 0; i < config.assertions.length; i++ ) {
168
- var assertion = config.assertions[i];
169
-
170
- var li = document.createElement("li");
171
- li.className = assertion.result ? "pass" : "fail";
172
- li.appendChild(document.createTextNode(assertion.message || "(no message)"));
173
- ol.appendChild( li );
174
-
175
- if ( assertion.result ) {
176
- good++;
177
- } else {
178
- bad++;
179
- config.stats.bad++;
180
- config.moduleStats.bad++;
181
- }
182
- }
183
-
184
- var b = document.createElement("strong");
185
- b.innerHTML = name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + config.assertions.length + ")</b>";
186
-
187
- addEvent(b, "click", function() {
188
- var next = b.nextSibling, display = next.style.display;
189
- next.style.display = display === "none" ? "block" : "none";
190
- });
191
-
192
- addEvent(b, "dblclick", function(e) {
193
- var target = e && e.target ? e.target : window.event.srcElement;
194
- if ( target.nodeName.toLowerCase() === "strong" ) {
195
- var text = "", node = target.firstChild;
196
-
197
- while ( node.nodeType === 3 ) {
198
- text += node.nodeValue;
199
- node = node.nextSibling;
200
- }
201
-
202
- text = text.replace(/(^\s*|\s*$)/g, "");
203
-
204
- if ( window.location ) {
205
- window.location.href = window.location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent(text);
206
- }
207
- }
208
- });
209
-
210
- var li = document.createElement("li");
211
- li.className = bad ? "fail" : "pass";
212
- li.appendChild( b );
213
- li.appendChild( ol );
214
- tests.appendChild( li );
215
-
216
- if ( bad ) {
217
- var toolbar = id("qunit-testrunner-toolbar");
218
- if ( toolbar ) {
219
- toolbar.style.display = "block";
220
- id("qunit-filter-pass").disabled = null;
221
- id("qunit-filter-missing").disabled = null;
222
- }
223
- }
224
-
225
- } else {
226
- for ( var i = 0; i < config.assertions.length; i++ ) {
227
- if ( !config.assertions[i].result ) {
228
- bad++;
229
- config.stats.bad++;
230
- config.moduleStats.bad++;
231
- }
232
- }
233
- }
234
-
235
- QUnit.testDone( testName, bad, config.assertions.length );
236
-
237
- if ( !window.setTimeout && !config.queue.length ) {
238
- done();
239
- }
240
- });
241
-
242
- if ( window.setTimeout && !config.doneTimer ) {
243
- config.doneTimer = window.setTimeout(function(){
244
- if ( !config.queue.length ) {
245
- done();
246
- } else {
247
- synchronize( done );
248
- }
249
- }, 13);
250
- }
251
  },
252
 
253
  /**
254
  * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
255
  */
256
  expect: function(asserts) {
257
- config.expected = asserts;
258
  },
259
 
260
  /**
@@ -262,10 +289,15 @@ var QUnit = {
262
  * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
263
  */
264
  ok: function(a, msg) {
265
- QUnit.log(a, msg);
266
-
267
- config.assertions.push({
268
- result: !!a,
 
 
 
 
 
269
  message: msg
270
  });
271
  },
@@ -283,32 +315,42 @@ var QUnit = {
283
  * @param String message (optional)
284
  */
285
  equal: function(actual, expected, message) {
286
- push(expected == actual, actual, expected, message);
287
  },
288
 
289
  notEqual: function(actual, expected, message) {
290
- push(expected != actual, actual, expected, message);
291
  },
292
 
293
- deepEqual: function(a, b, message) {
294
- push(QUnit.equiv(a, b), a, b, message);
295
  },
296
 
297
- notDeepEqual: function(a, b, message) {
298
- push(!QUnit.equiv(a, b), a, b, message);
299
  },
300
 
301
  strictEqual: function(actual, expected, message) {
302
- push(expected === actual, actual, expected, message);
303
  },
304
 
305
  notStrictEqual: function(actual, expected, message) {
306
- push(expected !== actual, actual, expected, message);
307
  },
308
-
 
 
 
 
 
 
 
 
 
 
309
  start: function() {
310
  // A slight delay, to avoid any current callbacks
311
- if ( window.setTimeout ) {
312
  window.setTimeout(function() {
313
  if ( config.timeout ) {
314
  clearTimeout(config.timeout);
@@ -326,57 +368,14 @@ var QUnit = {
326
  stop: function(timeout) {
327
  config.blocking = true;
328
 
329
- if ( timeout && window.setTimeout ) {
330
  config.timeout = window.setTimeout(function() {
331
  QUnit.ok( false, "Test timed out" );
332
  QUnit.start();
333
  }, timeout);
334
  }
335
- },
336
-
337
- /**
338
- * Resets the test setup. Useful for tests that modify the DOM.
339
- */
340
- reset: function() {
341
- if ( window.jQuery ) {
342
- jQuery("#main").html( config.fixture );
343
- jQuery.event.global = {};
344
- jQuery.ajaxSettings = extend({}, config.ajaxSettings);
345
- }
346
- },
347
-
348
- /**
349
- * Trigger an event on an element.
350
- *
351
- * @example triggerEvent( document.body, "click" );
352
- *
353
- * @param DOMElement elem
354
- * @param String type
355
- */
356
- triggerEvent: function( elem, type, event ) {
357
- if ( document.createEvent ) {
358
- event = document.createEvent("MouseEvents");
359
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
360
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
361
- elem.dispatchEvent( event );
362
 
363
- } else if ( elem.fireEvent ) {
364
- elem.fireEvent("on"+type);
365
- }
366
- },
367
-
368
- // Safe object type checking
369
- is: function( type, obj ) {
370
- return Object.prototype.toString.call( obj ) === "[object "+ type +"]";
371
- },
372
-
373
- // Logging callbacks
374
- done: function(failures, total) {},
375
- log: function(result, message) {},
376
- testStart: function(name) {},
377
- testDone: function(name, failures, total) {},
378
- moduleStart: function(name, testEnvironment) {},
379
- moduleDone: function(name, failures, total) {}
380
  };
381
 
382
  // Backwards compatibility, deprecated
@@ -426,11 +425,167 @@ if ( typeof exports === "undefined" || typeof require === "undefined" ) {
426
  exports.QUnit = QUnit;
427
  }
428
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
  if ( typeof document === "undefined" || document.readyState === "complete" ) {
430
  config.autorun = true;
431
  }
432
 
433
  addEvent(window, "load", function() {
 
 
434
  // Initialize the config, saving the execution queue
435
  var oldconfig = extend({}, config);
436
  QUnit.init();
@@ -442,6 +597,19 @@ addEvent(window, "load", function() {
442
  if ( userAgent ) {
443
  userAgent.innerHTML = navigator.userAgent;
444
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
445
 
446
  var toolbar = id("qunit-testrunner-toolbar");
447
  if ( toolbar ) {
@@ -465,57 +633,19 @@ addEvent(window, "load", function() {
465
  label.setAttribute("for", "qunit-filter-pass");
466
  label.innerHTML = "Hide passed tests";
467
  toolbar.appendChild( label );
468
-
469
- var missing = document.createElement("input");
470
- missing.type = "checkbox";
471
- missing.id = "qunit-filter-missing";
472
- missing.disabled = true;
473
- addEvent( missing, "click", function() {
474
- var li = document.getElementsByTagName("li");
475
- for ( var i = 0; i < li.length; i++ ) {
476
- if ( li[i].className.indexOf("fail") > -1 && li[i].innerHTML.indexOf('missing test - untested code is broken code') > - 1 ) {
477
- li[i].parentNode.parentNode.style.display = missing.checked ? "none" : "block";
478
- }
479
- }
480
- });
481
- toolbar.appendChild( missing );
482
-
483
- label = document.createElement("label");
484
- label.setAttribute("for", "qunit-filter-missing");
485
- label.innerHTML = "Hide missing tests (untested code is broken code)";
486
- toolbar.appendChild( label );
487
  }
488
 
489
- var main = id('main');
490
  if ( main ) {
491
  config.fixture = main.innerHTML;
492
  }
493
 
494
- if ( window.jQuery ) {
495
- config.ajaxSettings = window.jQuery.ajaxSettings;
496
  }
497
-
498
- QUnit.start();
499
  });
500
 
501
  function done() {
502
- if ( config.doneTimer && window.clearTimeout ) {
503
- window.clearTimeout( config.doneTimer );
504
- config.doneTimer = null;
505
- }
506
-
507
- if ( config.queue.length ) {
508
- config.doneTimer = window.setTimeout(function(){
509
- if ( !config.queue.length ) {
510
- done();
511
- } else {
512
- synchronize( done );
513
- }
514
- }, 13);
515
-
516
- return;
517
- }
518
-
519
  config.autorun = true;
520
 
521
  // Log the last module results
@@ -577,9 +707,41 @@ function validTest( name ) {
577
  return run;
578
  }
579
 
580
- function push(result, actual, expected, message) {
581
- message = message || (result ? "okay" : "failed");
582
- QUnit.ok( result, result ? message + ": " + QUnit.jsDump.parse(expected) : message + ", expected: " + QUnit.jsDump.parse(expected) + " result: " + QUnit.jsDump.parse(actual) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
583
  }
584
 
585
  function synchronize( callback ) {
@@ -596,12 +758,14 @@ function process() {
596
  while ( config.queue.length && !config.blocking ) {
597
  if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) {
598
  config.queue.shift()();
599
-
600
  } else {
601
- setTimeout( process, 13 );
602
  break;
603
  }
604
  }
 
 
 
605
  }
606
 
607
  function saveGlobal() {
@@ -621,13 +785,13 @@ function checkPollution( name ) {
621
  var newGlobals = diff( old, config.pollution );
622
  if ( newGlobals.length > 0 ) {
623
  ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
624
- config.expected++;
625
  }
626
 
627
  var deletedGlobals = diff( config.pollution, old );
628
  if ( deletedGlobals.length > 0 ) {
629
  ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
630
- config.expected++;
631
  }
632
  }
633
 
@@ -690,60 +854,11 @@ QUnit.equiv = function () {
690
  var callers = []; // stack to decide between skip/abort functions
691
  var parents = []; // stack to avoiding loops from circular referencing
692
 
693
-
694
- // Determine what is o.
695
- function hoozit(o) {
696
- if (QUnit.is("String", o)) {
697
- return "string";
698
-
699
- } else if (QUnit.is("Boolean", o)) {
700
- return "boolean";
701
-
702
- } else if (QUnit.is("Number", o)) {
703
-
704
- if (isNaN(o)) {
705
- return "nan";
706
- } else {
707
- return "number";
708
- }
709
-
710
- } else if (typeof o === "undefined") {
711
- return "undefined";
712
-
713
- // consider: typeof null === object
714
- } else if (o === null) {
715
- return "null";
716
-
717
- // consider: typeof [] === object
718
- } else if (QUnit.is( "Array", o)) {
719
- return "array";
720
-
721
- // consider: typeof new Date() === object
722
- } else if (QUnit.is( "Date", o)) {
723
- return "date";
724
-
725
- // consider: /./ instanceof Object;
726
- // /./ instanceof RegExp;
727
- // typeof /./ === "function"; // => false in IE and Opera,
728
- // true in FF and Safari
729
- } else if (QUnit.is( "RegExp", o)) {
730
- return "regexp";
731
-
732
- } else if (typeof o === "object") {
733
- return "object";
734
-
735
- } else if (QUnit.is( "Function", o)) {
736
- return "function";
737
- } else {
738
- return undefined;
739
- }
740
- }
741
-
742
  // Call the o related callback with the given arguments.
743
  function bindCallbacks(o, callbacks, args) {
744
- var prop = hoozit(o);
745
  if (prop) {
746
- if (hoozit(callbacks[prop]) === "function") {
747
  return callbacks[prop].apply(callbacks, args);
748
  } else {
749
  return callbacks[prop]; // or undefined
@@ -777,11 +892,11 @@ QUnit.equiv = function () {
777
  },
778
 
779
  "date": function (b, a) {
780
- return hoozit(b) === "date" && a.valueOf() === b.valueOf();
781
  },
782
 
783
  "regexp": function (b, a) {
784
- return hoozit(b) === "regexp" &&
785
  a.source === b.source && // the regex itself
786
  a.global === b.global && // and its modifers (gmi) ...
787
  a.ignoreCase === b.ignoreCase &&
@@ -802,7 +917,7 @@ QUnit.equiv = function () {
802
  var len;
803
 
804
  // b could be an object literal here
805
- if ( ! (hoozit(b) === "array")) {
806
  return false;
807
  }
808
 
@@ -880,7 +995,7 @@ QUnit.equiv = function () {
880
  return (function (a, b) {
881
  if (a === b) {
882
  return true; // catch the most you can
883
- } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || hoozit(a) !== hoozit(b)) {
884
  return false; // don't lose time with error prone cases
885
  } else {
886
  return bindCallbacks(a, callbacks, [b, a]);
@@ -953,7 +1068,7 @@ QUnit.jsDump = (function() {
953
  type = "date";
954
  } else if (QUnit.is("Function", obj)) {
955
  type = "function";
956
- } else if (obj.setInterval && obj.document && !obj.nodeType) {
957
  type = "window";
958
  } else if (obj.nodeType === 9) {
959
  type = "document";
@@ -1007,31 +1122,31 @@ QUnit.jsDump = (function() {
1007
  ret += ' ' + name;
1008
  ret += '(';
1009
 
1010
- ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');
1011
- return join( ret, this.parse(fn,'functionCode'), '}' );
1012
  },
1013
  array: array,
1014
  nodelist: array,
1015
  arguments: array,
1016
  object:function( map ) {
1017
  var ret = [ ];
1018
- this.up();
1019
  for ( var key in map )
1020
- ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) );
1021
- this.down();
1022
  return join( '{', ret, '}' );
1023
  },
1024
  node:function( node ) {
1025
- var open = this.HTML ? '&lt;' : '<',
1026
- close = this.HTML ? '&gt;' : '>';
1027
 
1028
  var tag = node.nodeName.toLowerCase(),
1029
  ret = open + tag;
1030
 
1031
- for ( var a in this.DOMAttrs ) {
1032
- var val = node[this.DOMAttrs[a]];
1033
  if ( val )
1034
- ret += ' ' + a + '=' + this.parse( val, 'attribute' );
1035
  }
1036
  return ret + close + open + '/' + tag + close;
1037
  },
@@ -1059,11 +1174,168 @@ QUnit.jsDump = (function() {
1059
  'class':'className'
1060
  },
1061
  HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
1062
- indentChar:' ',//indentation unit
1063
- multiline:false //if true, items in a collection, are separated by a \n, else just a space.
1064
  };
1065
 
1066
  return jsDump;
1067
  })();
1068
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1069
  })(this);
10
 
11
  (function(window) {
12
 
13
+ var defined = {
14
+ setTimeout: typeof window.setTimeout !== "undefined",
15
+ sessionStorage: (function() {
16
+ try {
17
+ return !!sessionStorage.getItem;
18
+ } catch(e){
19
+ return false;
20
+ }
21
+ })()
22
+ }
23
 
24
+ var testId = 0;
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
+ var Test = function(name, testName, expected, testEnvironmentArg, async, callback) {
27
+ this.name = name;
28
+ this.testName = testName;
29
+ this.expected = expected;
30
+ this.testEnvironmentArg = testEnvironmentArg;
31
+ this.async = async;
32
+ this.callback = callback;
33
+ this.assertions = [];
34
+ };
35
+ Test.prototype = {
36
+ init: function() {
37
+ var tests = id("qunit-tests");
38
+ if (tests) {
39
+ var b = document.createElement("strong");
40
+ b.innerHTML = "Running " + this.name;
41
+ var li = document.createElement("li");
42
+ li.appendChild( b );
43
+ li.id = this.id = "test-output" + testId++;
44
+ tests.appendChild( li );
45
+ }
46
+ },
47
+ setup: function() {
48
+ if (this.module != config.previousModule) {
49
+ if ( this.previousModule ) {
50
+ QUnit.moduleDone( this.module, config.moduleStats.bad, config.moduleStats.all );
51
+ }
52
+ config.previousModule = this.module;
53
+ config.moduleStats = { all: 0, bad: 0 };
54
+ QUnit.moduleStart( this.module, this.moduleTestEnvironment );
55
+ }
56
 
57
+ config.current = this;
58
+ this.testEnvironment = extend({
59
+ setup: function() {},
60
+ teardown: function() {}
61
+ }, this.moduleTestEnvironment);
62
+ if (this.testEnvironmentArg) {
63
+ extend(this.testEnvironment, this.testEnvironmentArg);
64
  }
65
 
66
+ QUnit.testStart( this.testName, this.testEnvironment );
67
+
68
+ // allow utility functions to access the current test environment
69
+ // TODO why??
70
+ QUnit.current_testEnvironment = this.testEnvironment;
71
+
72
+ try {
73
+ if ( !config.pollution ) {
74
+ saveGlobal();
75
+ }
76
+
77
+ this.testEnvironment.setup.call(this.testEnvironment);
78
+ } catch(e) {
79
+ // TODO use testName instead of name for no-markup message?
80
+ QUnit.ok( false, "Setup failed on " + this.name + ": " + e.message );
81
+ }
82
+ },
83
+ run: function() {
84
+ if ( this.async ) {
85
+ QUnit.stop();
86
  }
87
 
88
+ try {
89
+ this.callback.call(this.testEnvironment);
90
+ } catch(e) {
91
+ // TODO use testName instead of name for no-markup message?
92
+ fail("Test " + this.name + " died, exception and test follows", e, this.callback);
93
+ QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) );
94
+ // else next test will carry the responsibility
95
+ saveGlobal();
96
+
97
+ // Restart the tests if they're blocking
98
+ if ( config.blocking ) {
99
+ start();
100
+ }
101
  }
102
  },
103
+ teardown: function() {
104
+ try {
105
+ checkPollution();
106
+ this.testEnvironment.teardown.call(this.testEnvironment);
107
+ } catch(e) {
108
+ // TODO use testName instead of name for no-markup message?
109
+ QUnit.ok( false, "Teardown failed on " + this.name + ": " + e.message );
110
+ }
111
+ },
112
+ finish: function() {
113
+ if ( this.expected && this.expected != this.assertions.length ) {
114
+ QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
115
+ }
116
+
117
+ var good = 0, bad = 0,
118
+ tests = id("qunit-tests");
119
 
120
+ config.stats.all += this.assertions.length;
121
+ config.moduleStats.all += this.assertions.length;
122
+
123
+ if ( tests ) {
124
+ var ol = document.createElement("ol");
125
+
126
+ for ( var i = 0; i < this.assertions.length; i++ ) {
127
+ var assertion = this.assertions[i];
128
+
129
+ var li = document.createElement("li");
130
+ li.className = assertion.result ? "pass" : "fail";
131
+ li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed");
132
+ ol.appendChild( li );
133
+
134
+ if ( assertion.result ) {
135
+ good++;
136
+ } else {
137
+ bad++;
138
+ config.stats.bad++;
139
+ config.moduleStats.bad++;
140
+ }
141
  }
142
 
143
+ // store result when possible
144
+ defined.sessionStorage && sessionStorage.setItem("qunit-" + this.testName, bad);
145
+
146
+ if (bad == 0) {
147
+ ol.style.display = "none";
148
+ }
149
+
150
+ var b = document.createElement("strong");
151
+ b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
152
+
153
+ addEvent(b, "click", function() {
154
+ var next = b.nextSibling, display = next.style.display;
155
+ next.style.display = display === "none" ? "block" : "none";
156
+ });
157
+
158
+ addEvent(b, "dblclick", function(e) {
159
+ var target = e && e.target ? e.target : window.event.srcElement;
160
+ if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
161
+ target = target.parentNode;
162
+ }
163
+ if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
164
+ window.location.search = "?" + encodeURIComponent(getText([target]).replace(/\(.+\)$/, "").replace(/(^\s*|\s*$)/g, ""));
165
+ }
166
+ });
167
+
168
+ var li = id(this.id);
169
+ li.className = bad ? "fail" : "pass";
170
+ li.style.display = resultDisplayStyle(!bad);
171
+ li.removeChild( li.firstChild );
172
+ li.appendChild( b );
173
+ li.appendChild( ol );
174
+
175
+ if ( bad ) {
176
+ var toolbar = id("qunit-testrunner-toolbar");
177
+ if ( toolbar ) {
178
+ toolbar.style.display = "block";
179
+ id("qunit-filter-pass").disabled = null;
180
+ }
181
+ }
182
+
183
+ } else {
184
+ for ( var i = 0; i < this.assertions.length; i++ ) {
185
+ if ( !this.assertions[i].result ) {
186
+ bad++;
187
+ config.stats.bad++;
188
+ config.moduleStats.bad++;
189
+ }
190
+ }
191
+ }
192
 
193
+ try {
194
+ QUnit.reset();
195
+ } catch(e) {
196
+ // TODO use testName instead of name for no-markup message?
197
+ fail("reset() failed, following Test " + this.name + ", exception and reset fn follows", e, QUnit.reset);
198
+ }
199
+
200
+ QUnit.testDone( this.testName, bad, this.assertions.length );
201
+ },
202
+
203
+ queue: function() {
204
+ var test = this;
205
+ synchronize(function() {
206
+ test.init();
207
  });
208
+ function run() {
209
+ // each of these can by async
210
+ synchronize(function() {
211
+ test.setup();
212
+ });
213
+ synchronize(function() {
214
+ test.run();
215
+ });
216
+ synchronize(function() {
217
+ test.teardown();
218
+ });
219
+ synchronize(function() {
220
+ test.finish();
221
+ });
222
+ }
223
+ // defer when previous test run passed, if storage is available
224
+ var bad = defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.testName);
225
+ if (bad) {
226
+ run();
227
+ } else {
228
+ synchronize(run);
229
+ };
230
+ }
231
+
232
+ }
233
+
234
+ var QUnit = {
235
+
236
+ // call on start of module test to prepend name to all tests
237
+ module: function(name, testEnvironment) {
238
+ config.previousModule = config.currentModule;
239
+ config.currentModule = name;
240
+ config.currentModuleTestEnviroment = testEnvironment;
241
  },
242
 
243
  asyncTest: function(testName, expected, callback) {
250
  },
251
 
252
  test: function(testName, expected, callback, async) {
253
+ var name = '<span class="test-name">' + testName + '</span>', testEnvironmentArg;
254
 
255
  if ( arguments.length === 2 ) {
256
  callback = expected;
263
  }
264
 
265
  if ( config.currentModule ) {
266
+ name = '<span class="module-name">' + config.currentModule + "</span>: " + name;
267
  }
268
 
269
+ if ( !validTest(config.currentModule + ": " + testName) ) {
270
  return;
271
  }
272
+
273
+ var test = new Test(name, testName, expected, testEnvironmentArg, async, callback);
274
+ test.previousModule = config.previousModule;
275
+ test.module = config.currentModule;
276
+ test.moduleTestEnvironment = config.currentModuleTestEnviroment;
277
+ test.queue();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  },
279
 
280
  /**
281
  * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
282
  */
283
  expect: function(asserts) {
284
+ config.current.expected = asserts;
285
  },
286
 
287
  /**
289
  * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
290
  */
291
  ok: function(a, msg) {
292
+ a = !!a;
293
+ var details = {
294
+ result: a,
295
+ message: msg
296
+ };
297
+ msg = escapeHtml(msg);
298
+ QUnit.log(a, msg, details);
299
+ config.current.assertions.push({
300
+ result: a,
301
  message: msg
302
  });
303
  },
315
  * @param String message (optional)
316
  */
317
  equal: function(actual, expected, message) {
318
+ QUnit.push(expected == actual, actual, expected, message);
319
  },
320
 
321
  notEqual: function(actual, expected, message) {
322
+ QUnit.push(expected != actual, actual, expected, message);
323
  },
324
 
325
+ deepEqual: function(actual, expected, message) {
326
+ QUnit.push(QUnit.equiv(actual, expected), actual, expected, message);
327
  },
328
 
329
+ notDeepEqual: function(actual, expected, message) {
330
+ QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message);
331
  },
332
 
333
  strictEqual: function(actual, expected, message) {
334
+ QUnit.push(expected === actual, actual, expected, message);
335
  },
336
 
337
  notStrictEqual: function(actual, expected, message) {
338
+ QUnit.push(expected !== actual, actual, expected, message);
339
  },
340
+
341
+ raises: function(fn, message) {
342
+ try {
343
+ fn();
344
+ QUnit.ok( false, message );
345
+ }
346
+ catch (e) {
347
+ QUnit.ok( true, message );
348
+ }
349
+ },
350
+
351
  start: function() {
352
  // A slight delay, to avoid any current callbacks
353
+ if ( defined.setTimeout ) {
354
  window.setTimeout(function() {
355
  if ( config.timeout ) {
356
  clearTimeout(config.timeout);
368
  stop: function(timeout) {
369
  config.blocking = true;
370
 
371
+ if ( timeout && defined.setTimeout ) {
372
  config.timeout = window.setTimeout(function() {
373
  QUnit.ok( false, "Test timed out" );
374
  QUnit.start();
375
  }, timeout);
376
  }
377
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  };
380
 
381
  // Backwards compatibility, deprecated
425
  exports.QUnit = QUnit;
426
  }
427
 
428
+ // define these after exposing globals to keep them in these QUnit namespace only
429
+ extend(QUnit, {
430
+ config: config,
431
+
432
+ // Initialize the configuration options
433
+ init: function() {
434
+ extend(config, {
435
+ stats: { all: 0, bad: 0 },
436
+ moduleStats: { all: 0, bad: 0 },
437
+ started: +new Date,
438
+ updateRate: 1000,
439
+ blocking: false,
440
+ autostart: true,
441
+ autorun: false,
442
+ filters: [],
443
+ queue: []
444
+ });
445
+
446
+ var tests = id("qunit-tests"),
447
+ banner = id("qunit-banner"),
448
+ result = id("qunit-testresult");
449
+
450
+ if ( tests ) {
451
+ tests.innerHTML = "";
452
+ }
453
+
454
+ if ( banner ) {
455
+ banner.className = "";
456
+ }
457
+
458
+ if ( result ) {
459
+ result.parentNode.removeChild( result );
460
+ }
461
+ },
462
+
463
+ /**
464
+ * Resets the test setup. Useful for tests that modify the DOM.
465
+ *
466
+ * If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
467
+ */
468
+ reset: function() {
469
+ if ( window.jQuery ) {
470
+ jQuery( "#main, #qunit-fixture" ).html( config.fixture );
471
+ } else {
472
+ var main = id( 'main' ) || id( 'qunit-fixture' );
473
+ if ( main ) {
474
+ main.innerHTML = config.fixture;
475
+ }
476
+ }
477
+ },
478
+
479
+ /**
480
+ * Trigger an event on an element.
481
+ *
482
+ * @example triggerEvent( document.body, "click" );
483
+ *
484
+ * @param DOMElement elem
485
+ * @param String type
486
+ */
487
+ triggerEvent: function( elem, type, event ) {
488
+ if ( document.createEvent ) {
489
+ event = document.createEvent("MouseEvents");
490
+ event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
491
+ 0, 0, 0, 0, 0, false, false, false, false, 0, null);
492
+ elem.dispatchEvent( event );
493
+
494
+ } else if ( elem.fireEvent ) {
495
+ elem.fireEvent("on"+type);
496
+ }
497
+ },
498
+
499
+ // Safe object type checking
500
+ is: function( type, obj ) {
501
+ return QUnit.objectType( obj ) == type;
502
+ },
503
+
504
+ objectType: function( obj ) {
505
+ if (typeof obj === "undefined") {
506
+ return "undefined";
507
+
508
+ // consider: typeof null === object
509
+ }
510
+ if (obj === null) {
511
+ return "null";
512
+ }
513
+
514
+ var type = Object.prototype.toString.call( obj )
515
+ .match(/^\[object\s(.*)\]$/)[1] || '';
516
+
517
+ switch (type) {
518
+ case 'Number':
519
+ if (isNaN(obj)) {
520
+ return "nan";
521
+ } else {
522
+ return "number";
523
+ }
524
+ case 'String':
525
+ case 'Boolean':
526
+ case 'Array':
527
+ case 'Date':
528
+ case 'RegExp':
529
+ case 'Function':
530
+ return type.toLowerCase();
531
+ }
532
+ if (typeof obj === "object") {
533
+ return "object";
534
+ }
535
+ return undefined;
536
+ },
537
+
538
+ push: function(result, actual, expected, message) {
539
+ var details = {
540
+ result: result,
541
+ message: message,
542
+ actual: actual,
543
+ expected: expected
544
+ };
545
+
546
+ message = escapeHtml(message) || (result ? "okay" : "failed");
547
+ message = '<span class="test-message">' + message + "</span>";
548
+ expected = escapeHtml(QUnit.jsDump.parse(expected));
549
+ actual = escapeHtml(QUnit.jsDump.parse(actual));
550
+ var output = message + '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>';
551
+ if (actual != expected) {
552
+ output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>';
553
+ output += '<tr class="test-diff"><th>Diff: </th><td><pre>' + QUnit.diff(expected, actual) +'</pre></td></tr>';
554
+ }
555
+ if (!result) {
556
+ var source = sourceFromStacktrace();
557
+ if (source) {
558
+ details.source = source;
559
+ output += '<tr class="test-source"><th>Source: </th><td><pre>' + source +'</pre></td></tr>';
560
+ }
561
+ }
562
+ output += "</table>";
563
+
564
+ QUnit.log(result, message, details);
565
+
566
+ config.current.assertions.push({
567
+ result: !!result,
568
+ message: output
569
+ });
570
+ },
571
+
572
+ // Logging callbacks
573
+ begin: function() {},
574
+ done: function(failures, total) {},
575
+ log: function(result, message) {},
576
+ testStart: function(name, testEnvironment) {},
577
+ testDone: function(name, failures, total) {},
578
+ moduleStart: function(name, testEnvironment) {},
579
+ moduleDone: function(name, failures, total) {}
580
+ });
581
+
582
  if ( typeof document === "undefined" || document.readyState === "complete" ) {
583
  config.autorun = true;
584
  }
585
 
586
  addEvent(window, "load", function() {
587
+ QUnit.begin();
588
+
589
  // Initialize the config, saving the execution queue
590
  var oldconfig = extend({}, config);
591
  QUnit.init();
597
  if ( userAgent ) {
598
  userAgent.innerHTML = navigator.userAgent;
599
  }
600
+ var banner = id("qunit-header");
601
+ if ( banner ) {
602
+ var paramsIndex = location.href.lastIndexOf(location.search);
603
+ if ( paramsIndex > -1 ) {
604
+ var mainPageLocation = location.href.slice(0, paramsIndex);
605
+ if ( mainPageLocation == location.href ) {
606
+ banner.innerHTML = '<a href=""> ' + banner.innerHTML + '</a> ';
607
+ } else {
608
+ var testName = decodeURIComponent(location.search.slice(1));
609
+ banner.innerHTML = '<a href="' + mainPageLocation + '">' + banner.innerHTML + '</a> &#8250; <a href="">' + testName + '</a>';
610
+ }
611
+ }
612
+ }
613
 
614
  var toolbar = id("qunit-testrunner-toolbar");
615
  if ( toolbar ) {
633
  label.setAttribute("for", "qunit-filter-pass");
634
  label.innerHTML = "Hide passed tests";
635
  toolbar.appendChild( label );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
636
  }
637
 
638
+ var main = id('main') || id('qunit-fixture');
639
  if ( main ) {
640
  config.fixture = main.innerHTML;
641
  }
642
 
643
+ if (config.autostart) {
644
+ QUnit.start();
645
  }
 
 
646
  });
647
 
648
  function done() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
649
  config.autorun = true;
650
 
651
  // Log the last module results
707
  return run;
708
  }
709
 
710
+ // so far supports only Firefox, Chrome and Opera (buggy)
711
+ // could be extended in the future to use something like https://github.com/csnover/TraceKit
712
+ function sourceFromStacktrace() {
713
+ try {
714
+ throw new Error();
715
+ } catch ( e ) {
716
+ if (e.stacktrace) {
717
+ // Opera
718
+ return e.stacktrace.split("\n")[6];
719
+ } else if (e.stack) {
720
+ // Firefox, Chrome
721
+ return e.stack.split("\n")[4];
722
+ }
723
+ }
724
+ }
725
+
726
+ function resultDisplayStyle(passed) {
727
+ return passed && id("qunit-filter-pass") && id("qunit-filter-pass").checked ? 'none' : '';
728
+ }
729
+
730
+ function escapeHtml(s) {
731
+ if (!s) {
732
+ return "";
733
+ }
734
+ s = s + "";
735
+ return s.replace(/[\&"<>\\]/g, function(s) {
736
+ switch(s) {
737
+ case "&": return "&amp;";
738
+ case "\\": return "\\\\";
739
+ case '"': return '\"';
740
+ case "<": return "&lt;";
741
+ case ">": return "&gt;";
742
+ default: return s;
743
+ }
744
+ });
745
  }
746
 
747
  function synchronize( callback ) {
758
  while ( config.queue.length && !config.blocking ) {
759
  if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) {
760
  config.queue.shift()();
 
761
  } else {
762
+ window.setTimeout( process, 13 );
763
  break;
764
  }
765
  }
766
+ if (!config.blocking && !config.queue.length) {
767
+ done();
768
+ }
769
  }
770
 
771
  function saveGlobal() {
785
  var newGlobals = diff( old, config.pollution );
786
  if ( newGlobals.length > 0 ) {
787
  ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
788
+ config.current.expected++;
789
  }
790
 
791
  var deletedGlobals = diff( config.pollution, old );
792
  if ( deletedGlobals.length > 0 ) {
793
  ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
794
+ config.current.expected++;
795
  }
796
  }
797
 
854
  var callers = []; // stack to decide between skip/abort functions
855
  var parents = []; // stack to avoiding loops from circular referencing
856
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
857
  // Call the o related callback with the given arguments.
858
  function bindCallbacks(o, callbacks, args) {
859
+ var prop = QUnit.objectType(o);
860
  if (prop) {
861
+ if (QUnit.objectType(callbacks[prop]) === "function") {
862
  return callbacks[prop].apply(callbacks, args);
863
  } else {
864
  return callbacks[prop]; // or undefined
892
  },
893
 
894
  "date": function (b, a) {
895
+ return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf();
896
  },
897
 
898
  "regexp": function (b, a) {
899
+ return QUnit.objectType(b) === "regexp" &&
900
  a.source === b.source && // the regex itself
901
  a.global === b.global && // and its modifers (gmi) ...
902
  a.ignoreCase === b.ignoreCase &&
917
  var len;
918
 
919
  // b could be an object literal here
920
+ if ( ! (QUnit.objectType(b) === "array")) {
921
  return false;
922
  }
923
 
995
  return (function (a, b) {
996
  if (a === b) {
997
  return true; // catch the most you can
998
+ } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || QUnit.objectType(a) !== QUnit.objectType(b)) {
999
  return false; // don't lose time with error prone cases
1000
  } else {
1001
  return bindCallbacks(a, callbacks, [b, a]);
1068
  type = "date";
1069
  } else if (QUnit.is("Function", obj)) {
1070
  type = "function";
1071
+ } else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") {
1072
  type = "window";
1073
  } else if (obj.nodeType === 9) {
1074
  type = "document";
1122
  ret += ' ' + name;
1123
  ret += '(';
1124
 
1125
+ ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join('');
1126
+ return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' );
1127
  },
1128
  array: array,
1129
  nodelist: array,
1130
  arguments: array,
1131
  object:function( map ) {
1132
  var ret = [ ];
1133
+ QUnit.jsDump.up();
1134
  for ( var key in map )
1135
+ ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(map[key]) );
1136
+ QUnit.jsDump.down();
1137
  return join( '{', ret, '}' );
1138
  },
1139
  node:function( node ) {
1140
+ var open = QUnit.jsDump.HTML ? '&lt;' : '<',
1141
+ close = QUnit.jsDump.HTML ? '&gt;' : '>';
1142
 
1143
  var tag = node.nodeName.toLowerCase(),
1144
  ret = open + tag;
1145
 
1146
+ for ( var a in QUnit.jsDump.DOMAttrs ) {
1147
+ var val = node[QUnit.jsDump.DOMAttrs[a]];
1148
  if ( val )
1149
+ ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' );
1150
  }
1151
  return ret + close + open + '/' + tag + close;
1152
  },
1174
  'class':'className'
1175
  },
1176
  HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
1177
+ indentChar:' ',//indentation unit
1178
+ multiline:true //if true, items in a collection, are separated by a \n, else just a space.
1179
  };
1180
 
1181
  return jsDump;
1182
  })();
1183
 
1184
+ // from Sizzle.js
1185
+ function getText( elems ) {
1186
+ var ret = "", elem;
1187
+
1188
+ for ( var i = 0; elems[i]; i++ ) {
1189
+ elem = elems[i];
1190
+
1191
+ // Get the text from text nodes and CDATA nodes
1192
+ if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
1193
+ ret += elem.nodeValue;
1194
+
1195
+ // Traverse everything else, except comment nodes
1196
+ } else if ( elem.nodeType !== 8 ) {
1197
+ ret += getText( elem.childNodes );
1198
+ }
1199
+ }
1200
+
1201
+ return ret;
1202
+ };
1203
+
1204
+ /*
1205
+ * Javascript Diff Algorithm
1206
+ * By John Resig (http://ejohn.org/)
1207
+ * Modified by Chu Alan "sprite"
1208
+ *
1209
+ * Released under the MIT license.
1210
+ *
1211
+ * More Info:
1212
+ * http://ejohn.org/projects/javascript-diff-algorithm/
1213
+ *
1214
+ * Usage: QUnit.diff(expected, actual)
1215
+ *
1216
+ * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
1217
+ */
1218
+ QUnit.diff = (function() {
1219
+ function diff(o, n){
1220
+ var ns = new Object();
1221
+ var os = new Object();
1222
+
1223
+ for (var i = 0; i < n.length; i++) {
1224
+ if (ns[n[i]] == null)
1225
+ ns[n[i]] = {
1226
+ rows: new Array(),
1227
+ o: null
1228
+ };
1229
+ ns[n[i]].rows.push(i);
1230
+ }
1231
+
1232
+ for (var i = 0; i < o.length; i++) {
1233
+ if (os[o[i]] == null)
1234
+ os[o[i]] = {
1235
+ rows: new Array(),
1236
+ n: null
1237
+ };
1238
+ os[o[i]].rows.push(i);
1239
+ }
1240
+
1241
+ for (var i in ns) {
1242
+ if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) {
1243
+ n[ns[i].rows[0]] = {
1244
+ text: n[ns[i].rows[0]],
1245
+ row: os[i].rows[0]
1246
+ };
1247
+ o[os[i].rows[0]] = {
1248
+ text: o[os[i].rows[0]],
1249
+ row: ns[i].rows[0]
1250
+ };
1251
+ }
1252
+ }
1253
+
1254
+ for (var i = 0; i < n.length - 1; i++) {
1255
+ if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&
1256
+ n[i + 1] == o[n[i].row + 1]) {
1257
+ n[i + 1] = {
1258
+ text: n[i + 1],
1259
+ row: n[i].row + 1
1260
+ };
1261
+ o[n[i].row + 1] = {
1262
+ text: o[n[i].row + 1],
1263
+ row: i + 1
1264
+ };
1265
+ }
1266
+ }
1267
+
1268
+ for (var i = n.length - 1; i > 0; i--) {
1269
+ if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
1270
+ n[i - 1] == o[n[i].row - 1]) {
1271
+ n[i - 1] = {
1272
+ text: n[i - 1],
1273
+ row: n[i].row - 1
1274
+ };
1275
+ o[n[i].row - 1] = {
1276
+ text: o[n[i].row - 1],
1277
+ row: i - 1
1278
+ };
1279
+ }
1280
+ }
1281
+
1282
+ return {
1283
+ o: o,
1284
+ n: n
1285
+ };
1286
+ }
1287
+
1288
+ return function(o, n){
1289
+ o = o.replace(/\s+$/, '');
1290
+ n = n.replace(/\s+$/, '');
1291
+ var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
1292
+
1293
+ var str = "";
1294
+
1295
+ var oSpace = o.match(/\s+/g);
1296
+ if (oSpace == null) {
1297
+ oSpace = [" "];
1298
+ }
1299
+ else {
1300
+ oSpace.push(" ");
1301
+ }
1302
+ var nSpace = n.match(/\s+/g);
1303
+ if (nSpace == null) {
1304
+ nSpace = [" "];
1305
+ }
1306
+ else {
1307
+ nSpace.push(" ");
1308
+ }
1309
+
1310
+ if (out.n.length == 0) {
1311
+ for (var i = 0; i < out.o.length; i++) {
1312
+ str += '<del>' + out.o[i] + oSpace[i] + "</del>";
1313
+ }
1314
+ }
1315
+ else {
1316
+ if (out.n[0].text == null) {
1317
+ for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
1318
+ str += '<del>' + out.o[n] + oSpace[n] + "</del>";
1319
+ }
1320
+ }
1321
+
1322
+ for (var i = 0; i < out.n.length; i++) {
1323
+ if (out.n[i].text == null) {
1324
+ str += '<ins>' + out.n[i] + nSpace[i] + "</ins>";
1325
+ }
1326
+ else {
1327
+ var pre = "";
1328
+
1329
+ for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) {
1330
+ pre += '<del>' + out.o[n] + oSpace[n] + "</del>";
1331
+ }
1332
+ str += " " + out.n[i].text + nSpace[i] + pre;
1333
+ }
1334
+ }
1335
+ }
1336
+
1337
+ return str;
1338
+ };
1339
+ })();
1340
+
1341
  })(this);
lib/sprintf-0.7-beta1.js ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ sprintf() for JavaScript 0.7-beta1
3
+ http://www.diveintojavascript.com/projects/javascript-sprintf
4
+
5
+ Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
6
+ All rights reserved.
7
+
8
+ Redistribution and use in source and binary forms, with or without
9
+ modification, are permitted provided that the following conditions are met:
10
+ * Redistributions of source code must retain the above copyright
11
+ notice, this list of conditions and the following disclaimer.
12
+ * Redistributions in binary form must reproduce the above copyright
13
+ notice, this list of conditions and the following disclaimer in the
14
+ documentation and/or other materials provided with the distribution.
15
+ * Neither the name of sprintf() for JavaScript nor the
16
+ names of its contributors may be used to endorse or promote products
17
+ derived from this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY
23
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+
31
+ Changelog:
32
+ 2010.09.06 - 0.7-beta1
33
+ - features: vsprintf, support for named placeholders
34
+ - enhancements: format cache, reduced global namespace pollution
35
+
36
+ 2010.05.22 - 0.6:
37
+ - reverted to 0.4 and fixed the bug regarding the sign of the number 0
38
+ Note:
39
+ Thanks to Raphael Pigulla <raph (at] n3rd [dot) org> (http://www.n3rd.org/)
40
+ who warned me about a bug in 0.5, I discovered that the last update was
41
+ a regress. I appologize for that.
42
+
43
+ 2010.05.09 - 0.5:
44
+ - bug fix: 0 is now preceeded with a + sign
45
+ - bug fix: the sign was not at the right position on padded results (Kamal Abdali)
46
+ - switched from GPL to BSD license
47
+
48
+ 2007.10.21 - 0.4:
49
+ - unit test and patch (David Baird)
50
+
51
+ 2007.09.17 - 0.3:
52
+ - bug fix: no longer throws exception on empty paramenters (Hans Pufal)
53
+
54
+ 2007.09.11 - 0.2:
55
+ - feature: added argument swapping
56
+
57
+ 2007.04.03 - 0.1:
58
+ - initial release
59
+ **/
60
+
61
+ var sprintf = (function() {
62
+ function get_type(variable) {
63
+ return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
64
+ }
65
+ function str_repeat(input, multiplier) {
66
+ for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
67
+ return output.join('');
68
+ }
69
+
70
+ var str_format = function() {
71
+ if (!str_format.cache.hasOwnProperty(arguments[0])) {
72
+ str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
73
+ }
74
+ return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
75
+ };
76
+
77
+ str_format.format = function(parse_tree, argv) {
78
+ var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
79
+ for (i = 0; i < tree_length; i++) {
80
+ node_type = get_type(parse_tree[i]);
81
+ if (node_type === 'string') {
82
+ output.push(parse_tree[i]);
83
+ }
84
+ else if (node_type === 'array') {
85
+ match = parse_tree[i]; // convenience purposes only
86
+ if (match[2]) { // keyword argument
87
+ arg = argv[cursor];
88
+ for (k = 0; k < match[2].length; k++) {
89
+ if (!arg.hasOwnProperty(match[2][k])) {
90
+ throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
91
+ }
92
+ arg = arg[match[2][k]];
93
+ }
94
+ }
95
+ else if (match[1]) { // positional argument (explicit)
96
+ arg = argv[match[1]];
97
+ }
98
+ else { // positional argument (implicit)
99
+ arg = argv[cursor++];
100
+ }
101
+
102
+ if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
103
+ throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
104
+ }
105
+ switch (match[8]) {
106
+ case 'b': arg = arg.toString(2); break;
107
+ case 'c': arg = String.fromCharCode(arg); break;
108
+ case 'd': arg = parseInt(arg, 10); break;
109
+ case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
110
+ case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
111
+ case 'o': arg = arg.toString(8); break;
112
+ case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
113
+ case 'u': arg = Math.abs(arg); break;
114
+ case 'x': arg = arg.toString(16); break;
115
+ case 'X': arg = arg.toString(16).toUpperCase(); break;
116
+ }
117
+ arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
118
+ pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
119
+ pad_length = match[6] - String(arg).length;
120
+ pad = match[6] ? str_repeat(pad_character, pad_length) : '';
121
+ output.push(match[5] ? arg + pad : pad + arg);
122
+ }
123
+ }
124
+ return output.join('');
125
+ };
126
+
127
+ str_format.cache = {};
128
+
129
+ str_format.parse = function(fmt) {
130
+ var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
131
+ while (_fmt) {
132
+ if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
133
+ parse_tree.push(match[0]);
134
+ }
135
+ else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
136
+ parse_tree.push('%');
137
+ }
138
+ else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
139
+ if (match[2]) {
140
+ arg_names |= 1;
141
+ var field_list = [], replacement_field = match[2], field_match = [];
142
+ if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
143
+ field_list.push(field_match[1]);
144
+ while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
145
+ if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
146
+ field_list.push(field_match[1]);
147
+ }
148
+ else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
149
+ field_list.push(field_match[1]);
150
+ }
151
+ else {
152
+ throw('[sprintf] huh?');
153
+ }
154
+ }
155
+ }
156
+ else {
157
+ throw('[sprintf] huh?');
158
+ }
159
+ match[2] = field_list;
160
+ }
161
+ else {
162
+ arg_names |= 2;
163
+ }
164
+ if (arg_names === 3) {
165
+ throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
166
+ }
167
+ parse_tree.push(match);
168
+ }
169
+ else {
170
+ throw('[sprintf] huh?');
171
+ }
172
+ _fmt = _fmt.substring(match[0].length);
173
+ }
174
+ return parse_tree;
175
+ };
176
+
177
+ return str_format;
178
+ })();
179
+
180
+ var vsprintf = function(fmt, argv) {
181
+ argv.unshift(fmt);
182
+ return sprintf.apply(null, argv);
183
+ };
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: cvernon, justinstresslimit, MaryVogt, zgrossbart
3
  Tags: posts, post, calendar, AJAX, admin, administration
4
  Requires at least: 2.8.5
5
- Tested up to: 3.0.1
6
- Stable tag: 1.2
7
 
8
  The Editorial Calendar makes it possible to see all your posts and drag and drop them to manage your blog.
9
 
@@ -38,13 +38,13 @@ Thank you to everyone who has given us feedback and helped us improve this plugi
38
  1. <b>Backup your WordPress database</b>.
39
  1. Upload the plugin directory <code>editorial-calendar</code> to the <code>wp-content/plugins</code> directory.
40
  1. Activate the plugin through the 'Plugins' menu in WordPress.
41
- 1. Click the new 'Calendar' option under the 'Posts' menu.
42
 
43
  == Frequently Asked Questions ==
44
 
45
  = What is an editorial calendar? =
46
 
47
- An editorial calendar is simply a plan for your blog. It is thinking ahead about what you're going to write. There's a detailed explanation of editorial calendars at <a href="http://www.copyblogger.com/editorial-calendar/">The Easy-to-Use Tool that Helps You Build a Breakthrough Blog</a>.
48
 
49
  = What are other people saying about the calendar? =
50
 
@@ -103,7 +103,7 @@ The editorial calendar follows the Week Starts On preference on the WordPress Ge
103
 
104
  = What languages does the calendar support? =
105
 
106
- The calendar is available in Croatian, Czechoslovakian, English, French, and Greek.
107
 
108
  = Can I add new languages? =
109
 
@@ -148,9 +148,16 @@ Moving published posts can cause problems with some RSS feeds and is generally n
148
  3. Drag and drop posts to easily change dates and take control of your blog.
149
  4. Create, edit, and schedule posts in one simple quickedit dialog.
150
  5. Show as much or as little of your blog as you like.
 
151
 
152
  == Changelog ==
153
 
 
 
 
 
 
 
154
  = 1.2 =
155
  * We are now smarter about the way we scroll the calendar day to show the action links when the day has scroll bars.
156
  * The calendar is now doing a better job determining the height of the list of posts in each day so the posts don't overlap other days.
@@ -162,7 +169,7 @@ Moving published posts can cause problems with some RSS feeds and is generally n
162
  * Changed the text of the edit link on published posts from Republish to Edit.
163
 
164
  = 1.0 =
165
- * Fixed a scrolling issue where you can't click the action links on the last post if the individual day showing a scroll bar.
166
 
167
  = 0.9 =
168
  * The calendar now uses the QUnit unit test framework to make sure the calendar maintains high quality in every release. You can see the <a href="http://www.zackgrossbart.com/extras/sandbox/wp-admin/edit.php?page=cal&qunit=true">tests run</a> on our integration blog or run them on your own blog by adding &qunit=true to the end of the URL for the calendar.
2
  Contributors: cvernon, justinstresslimit, MaryVogt, zgrossbart
3
  Tags: posts, post, calendar, AJAX, admin, administration
4
  Requires at least: 2.8.5
5
+ Tested up to: 3.0.4
6
+ Stable tag: 1.3
7
 
8
  The Editorial Calendar makes it possible to see all your posts and drag and drop them to manage your blog.
9
 
38
  1. <b>Backup your WordPress database</b>.
39
  1. Upload the plugin directory <code>editorial-calendar</code> to the <code>wp-content/plugins</code> directory.
40
  1. Activate the plugin through the 'Plugins' menu in WordPress.
41
+ 1. Click the new 'Calendar' option under the 'Posts' menu or any other custom post types.
42
 
43
  == Frequently Asked Questions ==
44
 
45
  = What is an editorial calendar? =
46
 
47
+ An editorial calendar is simply a plan for your blog. It is thinking ahead about what you're going to write. There's a detailed explanation of editorial calendars at <a href="http://www.copyblogger.com/editorial-calendar/">The Easy-to-Use Tool that Helps You Build a Breakthrough Blog</a> from <a href="http://www.copyblogger.com/">Copyblogger</a>.
48
 
49
  = What are other people saying about the calendar? =
50
 
103
 
104
  = What languages does the calendar support? =
105
 
106
+ The calendar is available in Brazilian Portuguese, Croatian, Czechoslovakian, English, French, and Greek.
107
 
108
  = Can I add new languages? =
109
 
148
  3. Drag and drop posts to easily change dates and take control of your blog.
149
  4. Create, edit, and schedule posts in one simple quickedit dialog.
150
  5. Show as much or as little of your blog as you like.
151
+ 6. Use a special calendar for each custom post type on your blog.
152
 
153
  == Changelog ==
154
 
155
+ = 1.3 =
156
+ * The Editorial Calendar will now show up for each custom post type and support a separate calendar for each type.
157
+ * We are now disabling the save button on the quick edit dialog after it is pressed and before the post saves to prevent duplicate posts if the user presses the button twice in a row.
158
+ * Upgraded the to the latest version of QUnit for our unit test framework
159
+ * The calendar now supports Brazilian Portuguese. Thanks to Janio Sarmento who uses the Editorial Calendar on his site <a href="http://janio.sarmento.org/">O Blogue do Janio</a>.
160
+
161
  = 1.2 =
162
  * We are now smarter about the way we scroll the calendar day to show the action links when the day has scroll bars.
163
  * The calendar is now doing a better job determining the height of the list of posts in each day so the posts don't overlap other days.
169
  * Changed the text of the edit link on published posts from Republish to Edit.
170
 
171
  = 1.0 =
172
+ * Fixed a scrolling issue that prevented cliking the action links on the last post if the individual day showed a scroll bar.
173
 
174
  = 0.9 =
175
  * The calendar now uses the QUnit unit test framework to make sure the calendar maintains high quality in every release. You can see the <a href="http://www.zackgrossbart.com/extras/sandbox/wp-admin/edit.php?page=cal&qunit=true">tests run</a> on our integration blog or run them on your own blog by adding &qunit=true to the end of the URL for the calendar.
screenshot-1.png CHANGED
Binary file
screenshot-2.png CHANGED
Binary file
screenshot-3.png CHANGED
Binary file
screenshot-4.png CHANGED
Binary file
screenshot-5.png CHANGED
Binary file
screenshot-6.png ADDED
Binary file