typo 3.99.3 → 3.99.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/README +1 -39
  2. data/app/controllers/admin/feedback_controller.rb +71 -0
  3. data/app/controllers/articles_controller.rb +11 -0
  4. data/app/helpers/admin/feedback_helper.rb +9 -0
  5. data/app/helpers/application_helper.rb +5 -1
  6. data/app/models/article.rb +21 -1
  7. data/app/models/blog.rb +25 -1
  8. data/app/models/comment.rb +12 -2
  9. data/app/models/content.rb +63 -4
  10. data/app/models/ping.rb +3 -3
  11. data/app/models/text_filter.rb +1 -1
  12. data/app/models/trackback.rb +12 -1
  13. data/app/views/admin/content/_form.rhtml +2 -2
  14. data/app/views/admin/feedback/_item.rhtml +15 -0
  15. data/app/views/admin/feedback/list.rhtml +46 -0
  16. data/app/views/admin/general/index.rhtml +26 -0
  17. data/app/views/articles/_comment.rhtml +3 -0
  18. data/app/views/articles/read.rhtml +2 -2
  19. data/app/views/layouts/administration.rhtml +1 -0
  20. data/bin/typo +3 -23
  21. data/components/plugins/sidebars/archives_controller.rb +1 -1
  22. data/components/plugins/sidebars/xml_controller.rb +1 -1
  23. data/components/plugins/textfilters/flickr_controller.rb +1 -1
  24. data/components/plugins/textfilters/sparkline_controller.rb +3 -2
  25. data/components/plugins/textfilters/textile_controller.rb +6 -0
  26. data/config/mongrel.conf +2 -0
  27. data/db/converters/wordpress2.rb +291 -0
  28. data/db/migrate/022_superclass_trackbacks.rb +1 -0
  29. data/db/migrate/023_superclass_pages.rb +4 -3
  30. data/db/schema.rb +4 -4
  31. data/doc/Installer.txt +81 -6
  32. data/doc/typo-4.0-release-notes.txt +135 -0
  33. data/installer/rails-installer.rb +22 -3
  34. data/installer/rails-installer/commands.rb +27 -26
  35. data/installer/rails-installer/web-servers.rb +2 -0
  36. data/lib/sidebars/plugin.rb +10 -8
  37. data/lib/tasks/release.rake +1 -1
  38. data/lib/typo_version.rb +1 -1
  39. data/public/javascripts/dragdrop.js +252 -63
  40. data/public/javascripts/effects.js +15 -10
  41. data/public/javascripts/prototype.js +59 -38
  42. data/public/javascripts/typo.js +10 -0
  43. data/public/stylesheets/administration.css +111 -66
  44. data/test/functional/admin/feedback_controller_test.rb +24 -0
  45. data/test/mocks/test/http_mock.rb +2 -1
  46. data/test/unit/article_test.rb +6 -0
  47. data/test/unit/comment_test.rb +12 -9
  48. data/test/unit/ping_test.rb +1 -1
  49. data/test/unit/trackback_test.rb +3 -5
  50. data/themes/azure/stylesheets/azure.css +7 -0
  51. data/themes/scribbish/views/articles/_article.rhtml +1 -1
  52. data/themes/scribbish/views/articles/_comment_form.rhtml +1 -1
  53. data/vendor/akismet/Akismet.rb +36 -17
  54. data/vendor/plugins/expiring_action_cache/lib/actionparamcache.rb +3 -1
  55. metadata +11 -42
  56. data/installer/rails-installer/web-server.rb +0 -108
  57. data/tmp/cache/META/DATA/ACTION_PARAM/10.1.0.181/articles/index/.cache +0 -537
  58. data/tmp/cache/META/DATA/ACTION_PARAM/localhost/articles/index/.cache +0 -537
  59. data/tmp/cache/META/DATA/ACTION_PARAM/localhost/xml/feed/format=atom&type=feed.cache +0 -671
  60. data/tmp/cache/META/DATA/ACTION_PARAM/localhost/xml/feed/format=rss20&type=feed.cache +0 -401
  61. data/tmp/cache/META/META/ACTION_PARAM/10.1.0.181/articles/index/.cache +0 -2
  62. data/tmp/cache/META/META/ACTION_PARAM/localhost/articles/index/.cache +0 -2
  63. data/tmp/cache/META/META/ACTION_PARAM/localhost/xml/feed/format=atom&type=feed.cache +0 -2
  64. data/tmp/cache/META/META/ACTION_PARAM/localhost/xml/feed/format=rss20&type=feed.cache +0 -2
@@ -34,6 +34,7 @@ class RailsInstaller
34
34
  args['-e'] = installer.config['rails-environment']
35
35
  args['-d'] = foreground
36
36
  args['-P'] = pid_file(installer)
37
+ args['--prefix'] = installer.config['url-prefix']
37
38
 
38
39
  # Remove keys with nil values
39
40
  args.delete_if {|k,v| v==nil}
@@ -71,6 +72,7 @@ class RailsInstaller
71
72
  args['-a'] = installer.config['bind-address']
72
73
  args['-e'] = installer.config['rails-environment']
73
74
  args['-N'] = installer.config['threads']
75
+ args['--prefix'] = installer.config['url-prefix']
74
76
 
75
77
  # Remove keys with nil values
76
78
  args.delete_if {|k,v| v==nil}
@@ -100,12 +100,8 @@ module Sidebars
100
100
 
101
101
  class Sidebars::Plugin < ApplicationController
102
102
  include ApplicationHelper
103
-
104
103
  helper :theme
105
104
 
106
- # skip_before_filter :get_the_blog_object
107
- # skip_after_filter :flush_the_blog_object
108
-
109
105
  @@subclasses = { }
110
106
 
111
107
  class << self
@@ -127,7 +123,6 @@ module Sidebars
127
123
  end
128
124
  end
129
125
 
130
-
131
126
  # The name that needs to be used when refering to the plugin's
132
127
  # controller in render statements
133
128
  def component_name
@@ -197,17 +192,18 @@ module Sidebars
197
192
  def default_helper_module!
198
193
  end
199
194
  end
200
-
195
+
201
196
  def index
202
197
  @sidebar=params['sidebar']
203
- @sb_config = @sidebar.config || self.class.default_config
198
+ set_config
199
+ @sb_config = @sidebar.config
204
200
  content
205
201
  render :action=>'content' unless performed?
206
202
  end
207
203
 
208
204
  def configure_wrapper
209
205
  @sidebar=params['sidebar']
210
- @sidebar.config ||= (self.class.default_config)
206
+ set_config
211
207
  configure
212
208
  render :action=>'configure' unless performed?
213
209
  end
@@ -222,6 +218,12 @@ module Sidebars
222
218
  end
223
219
 
224
220
  private
221
+ def set_config
222
+ @sidebar.config ||= {}
223
+ @sidebar.config = self.class.default_config.dup.merge(@sidebar.config)
224
+ @sidebar.config ||= (self.class.default_config)
225
+ end
226
+
225
227
  def sb_config(key)
226
228
  config = @sidebar.class.default_config
227
229
  config.merge!(@sidebar.config || {})
@@ -1,7 +1,7 @@
1
1
  require 'rake/gempackagetask'
2
2
  require 'rake/contrib/rubyforgepublisher'
3
3
 
4
- PKG_VERSION = "3.99.3"
4
+ PKG_VERSION = "3.99.4"
5
5
  PKG_NAME = "typo"
6
6
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
7
7
  RUBY_FORGE_PROJECT = 'typo'
data/lib/typo_version.rb CHANGED
@@ -1 +1 @@
1
- TYPO_VERSION = '3.99.3'
1
+ TYPO_VERSION = '3.99.4'
@@ -1,4 +1,5 @@
1
1
  // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2
+ // (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
2
3
  //
3
4
  // See scriptaculous.js for full license.
4
5
 
@@ -15,7 +16,8 @@ var Droppables = {
15
16
  element = $(element);
16
17
  var options = Object.extend({
17
18
  greedy: true,
18
- hoverclass: null
19
+ hoverclass: null,
20
+ tree: false
19
21
  }, arguments[1] || {});
20
22
 
21
23
  // cache containers
@@ -37,12 +39,27 @@ var Droppables = {
37
39
 
38
40
  this.drops.push(options);
39
41
  },
42
+
43
+ findDeepestChild: function(drops) {
44
+ deepest = drops[0];
45
+
46
+ for (i = 1; i < drops.length; ++i)
47
+ if (Element.isParent(drops[i].element, deepest.element))
48
+ deepest = drops[i];
49
+
50
+ return deepest;
51
+ },
40
52
 
41
53
  isContained: function(element, drop) {
42
- var parentNode = element.parentNode;
43
- return drop._containers.detect(function(c) { return parentNode == c });
54
+ var containmentNode;
55
+ if(drop.tree) {
56
+ containmentNode = element.treeNode;
57
+ } else {
58
+ containmentNode = element.parentNode;
59
+ }
60
+ return drop._containers.detect(function(c) { return containmentNode == c });
44
61
  },
45
-
62
+
46
63
  isAffected: function(point, element, drop) {
47
64
  return (
48
65
  (drop.element!=element) &&
@@ -68,18 +85,22 @@ var Droppables = {
68
85
 
69
86
  show: function(point, element) {
70
87
  if(!this.drops.length) return;
88
+ var affected = [];
71
89
 
72
90
  if(this.last_active) this.deactivate(this.last_active);
73
91
  this.drops.each( function(drop) {
74
- if(Droppables.isAffected(point, element, drop)) {
75
- if(drop.onHover)
76
- drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
77
- if(drop.greedy) {
78
- Droppables.activate(drop);
79
- throw $break;
80
- }
81
- }
92
+ if(Droppables.isAffected(point, element, drop))
93
+ affected.push(drop);
82
94
  });
95
+
96
+ if(affected.length>0) {
97
+ drop = Droppables.findDeepestChild(affected);
98
+ Position.within(drop.element, point[0], point[1]);
99
+ if(drop.onHover)
100
+ drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
101
+
102
+ Droppables.activate(drop);
103
+ }
83
104
  },
84
105
 
85
106
  fire: function(event, element) {
@@ -207,8 +228,10 @@ Draggable.prototype = {
207
228
 
208
229
  this.element = $(element);
209
230
 
210
- if(options.handle && (typeof options.handle == 'string'))
211
- this.handle = Element.childrenWithClassName(this.element, options.handle, true)[0];
231
+ if(options.handle && (typeof options.handle == 'string')) {
232
+ var h = Element.childrenWithClassName(this.element, options.handle, true);
233
+ if(h.length>0) this.handle = h[0];
234
+ }
212
235
  if(!this.handle) this.handle = $(options.handle);
213
236
  if(!this.handle) this.handle = this.element;
214
237
 
@@ -412,6 +435,7 @@ Draggable.prototype = {
412
435
  if(this.scrollInterval) {
413
436
  clearInterval(this.scrollInterval);
414
437
  this.scrollInterval = null;
438
+ Draggables._lastScrollPointer = null;
415
439
  }
416
440
  },
417
441
 
@@ -440,7 +464,14 @@ Draggable.prototype = {
440
464
  Position.prepare();
441
465
  Droppables.show(Draggables._lastPointer, this.element);
442
466
  Draggables.notify('onDrag', this);
443
- this.draw(Draggables._lastPointer);
467
+ Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
468
+ Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
469
+ Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
470
+ if (Draggables._lastScrollPointer[0] < 0)
471
+ Draggables._lastScrollPointer[0] = 0;
472
+ if (Draggables._lastScrollPointer[1] < 0)
473
+ Draggables._lastScrollPointer[1] = 0;
474
+ this.draw(Draggables._lastScrollPointer);
444
475
 
445
476
  if(this.options.change) this.options.change(this);
446
477
  },
@@ -492,30 +523,41 @@ SortableObserver.prototype = {
492
523
  }
493
524
 
494
525
  var Sortable = {
495
- sortables: new Array(),
526
+ sortables: {},
496
527
 
497
- options: function(element){
498
- element = $(element);
499
- return this.sortables.detect(function(s) { return s.element == element });
528
+ _findRootElement: function(element) {
529
+ while (element.tagName != "BODY") {
530
+ if(element.id && Sortable.sortables[element.id]) return element;
531
+ element = element.parentNode;
532
+ }
533
+ },
534
+
535
+ options: function(element) {
536
+ element = Sortable._findRootElement($(element));
537
+ if(!element) return;
538
+ return Sortable.sortables[element.id];
500
539
  },
501
540
 
502
541
  destroy: function(element){
503
- element = $(element);
504
- this.sortables.findAll(function(s) { return s.element == element }).each(function(s){
542
+ var s = Sortable.options(element);
543
+
544
+ if(s) {
505
545
  Draggables.removeObserver(s.element);
506
546
  s.droppables.each(function(d){ Droppables.remove(d) });
507
547
  s.draggables.invoke('destroy');
508
- });
509
- this.sortables = this.sortables.reject(function(s) { return s.element == element });
548
+
549
+ delete Sortable.sortables[s.element.id];
550
+ }
510
551
  },
511
-
552
+
512
553
  create: function(element) {
513
554
  element = $(element);
514
555
  var options = Object.extend({
515
556
  element: element,
516
557
  tag: 'li', // assumes li children, override with tag: 'tagname'
517
558
  dropOnEmpty: false,
518
- tree: false, // fixme: unimplemented
559
+ tree: false,
560
+ treeTag: 'ul',
519
561
  overlap: 'vertical', // one of 'vertical', 'horizontal'
520
562
  constraint: 'vertical', // one of 'vertical', 'horizontal', false
521
563
  containment: element, // also takes array of elements (or id's); or false
@@ -565,9 +607,17 @@ var Sortable = {
565
607
  var options_for_droppable = {
566
608
  overlap: options.overlap,
567
609
  containment: options.containment,
610
+ tree: options.tree,
568
611
  hoverclass: options.hoverclass,
569
- onHover: Sortable.onHover,
570
- greedy: !options.dropOnEmpty
612
+ onHover: Sortable.onHover
613
+ //greedy: !options.dropOnEmpty
614
+ }
615
+
616
+ var options_for_tree = {
617
+ onHover: Sortable.onEmptyHover,
618
+ overlap: options.overlap,
619
+ containment: options.containment,
620
+ hoverclass: options.hoverclass
571
621
  }
572
622
 
573
623
  // fix for gecko engine
@@ -576,12 +626,9 @@ var Sortable = {
576
626
  options.draggables = [];
577
627
  options.droppables = [];
578
628
 
579
- // make it so
580
-
581
629
  // drop on empty handling
582
- if(options.dropOnEmpty) {
583
- Droppables.add(element,
584
- {containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false});
630
+ if(options.dropOnEmpty || options.tree) {
631
+ Droppables.add(element, options_for_tree);
585
632
  options.droppables.push(element);
586
633
  }
587
634
 
@@ -592,11 +639,20 @@ var Sortable = {
592
639
  options.draggables.push(
593
640
  new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
594
641
  Droppables.add(e, options_for_droppable);
642
+ if(options.tree) e.treeNode = element;
595
643
  options.droppables.push(e);
596
644
  });
645
+
646
+ if(options.tree) {
647
+ (Sortable.findTreeElements(element, options) || []).each( function(e) {
648
+ Droppables.add(e, options_for_tree);
649
+ e.treeNode = element;
650
+ options.droppables.push(e);
651
+ });
652
+ }
597
653
 
598
654
  // keep reference
599
- this.sortables.push(options);
655
+ this.sortables[element.id] = options;
600
656
 
601
657
  // for onupdate
602
658
  Draggables.addObserver(new SortableObserver(element, options.onUpdate));
@@ -605,24 +661,21 @@ var Sortable = {
605
661
 
606
662
  // return all suitable-for-sortable elements in a guaranteed order
607
663
  findElements: function(element, options) {
608
- if(!element.hasChildNodes()) return null;
609
- var elements = [];
610
- var only = options.only ? [options.only].flatten() : null;
611
- $A(element.childNodes).each( function(e) {
612
- if(e.tagName && e.tagName.toUpperCase()==options.tag.toUpperCase() &&
613
- (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
614
- elements.push(e);
615
- if(options.tree) {
616
- var grandchildren = this.findElements(e, options);
617
- if(grandchildren) elements.push(grandchildren);
618
- }
619
- });
620
-
621
- return (elements.length>0 ? elements.flatten() : null);
664
+ return Element.findChildren(
665
+ element, options.only, options.tree ? true : false, options.tag);
666
+ },
667
+
668
+ findTreeElements: function(element, options) {
669
+ return Element.findChildren(
670
+ element, options.only, options.tree ? true : false, options.treeTag);
622
671
  },
623
672
 
624
673
  onHover: function(element, dropon, overlap) {
625
- if(overlap>0.5) {
674
+ if(Element.isParent(dropon, element)) return;
675
+
676
+ if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
677
+ return;
678
+ } else if(overlap>0.5) {
626
679
  Sortable.mark(dropon, 'before');
627
680
  if(dropon.previousSibling != element) {
628
681
  var oldParentNode = element.parentNode;
@@ -645,13 +698,37 @@ var Sortable = {
645
698
  }
646
699
  }
647
700
  },
648
-
649
- onEmptyHover: function(element, dropon) {
650
- if(element.parentNode!=dropon) {
651
- var oldParentNode = element.parentNode;
652
- dropon.appendChild(element);
701
+
702
+ onEmptyHover: function(element, dropon, overlap) {
703
+ var oldParentNode = element.parentNode;
704
+ var droponOptions = Sortable.options(dropon);
705
+
706
+ if(!Element.isParent(dropon, element)) {
707
+ var index;
708
+
709
+ var children = Sortable.findElements(dropon, {tag: droponOptions.tag});
710
+ var child = null;
711
+
712
+ if(children) {
713
+ var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
714
+
715
+ for (index = 0; index < children.length; index += 1) {
716
+ if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
717
+ offset -= Element.offsetSize (children[index], droponOptions.overlap);
718
+ } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
719
+ child = index + 1 < children.length ? children[index + 1] : null;
720
+ break;
721
+ } else {
722
+ child = children[index];
723
+ break;
724
+ }
725
+ }
726
+ }
727
+
728
+ dropon.insertBefore(element, child);
729
+
653
730
  Sortable.options(oldParentNode).onChange(element);
654
- Sortable.options(dropon).onChange(element);
731
+ droponOptions.onChange(element);
655
732
  }
656
733
  },
657
734
 
@@ -683,6 +760,75 @@ var Sortable = {
683
760
 
684
761
  Element.show(Sortable._marker);
685
762
  },
763
+
764
+ _tree: function(element, options, parent) {
765
+ var children = Sortable.findElements(element, options) || [];
766
+
767
+ for (var i = 0; i < children.length; ++i) {
768
+ var match = children[i].id.match(options.format);
769
+
770
+ if (!match) continue;
771
+
772
+ var child = {
773
+ id: encodeURIComponent(match ? match[1] : null),
774
+ element: element,
775
+ parent: parent,
776
+ children: new Array,
777
+ position: parent.children.length,
778
+ container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase())
779
+ }
780
+
781
+ /* Get the element containing the children and recurse over it */
782
+ if (child.container)
783
+ this._tree(child.container, options, child)
784
+
785
+ parent.children.push (child);
786
+ }
787
+
788
+ return parent;
789
+ },
790
+
791
+ /* Finds the first element of the given tag type within a parent element.
792
+ Used for finding the first LI[ST] within a L[IST]I[TEM].*/
793
+ _findChildrenElement: function (element, containerTag) {
794
+ if (element && element.hasChildNodes)
795
+ for (var i = 0; i < element.childNodes.length; ++i)
796
+ if (element.childNodes[i].tagName == containerTag)
797
+ return element.childNodes[i];
798
+
799
+ return null;
800
+ },
801
+
802
+ tree: function(element) {
803
+ element = $(element);
804
+ var sortableOptions = this.options(element);
805
+ var options = Object.extend({
806
+ tag: sortableOptions.tag,
807
+ treeTag: sortableOptions.treeTag,
808
+ only: sortableOptions.only,
809
+ name: element.id,
810
+ format: sortableOptions.format
811
+ }, arguments[1] || {});
812
+
813
+ var root = {
814
+ id: null,
815
+ parent: null,
816
+ children: new Array,
817
+ container: element,
818
+ position: 0
819
+ }
820
+
821
+ return Sortable._tree (element, options, root);
822
+ },
823
+
824
+ /* Construct a [i] index for a particular node */
825
+ _constructIndex: function(node) {
826
+ var index = '';
827
+ do {
828
+ if (node.id) index = '[' + node.position + ']' + index;
829
+ } while ((node = node.parent) != null);
830
+ return index;
831
+ },
686
832
 
687
833
  sequence: function(element) {
688
834
  element = $(element);
@@ -705,20 +851,63 @@ var Sortable = {
705
851
  });
706
852
 
707
853
  new_sequence.each(function(ident) {
708
- var n = nodeMap[ident];
709
- if (n) {
710
- n[1].appendChild(n[0]);
711
- delete nodeMap[ident];
712
- }
854
+ var n = nodeMap[ident];
855
+ if (n) {
856
+ n[1].appendChild(n[0]);
857
+ delete nodeMap[ident];
858
+ }
713
859
  });
714
860
  },
715
-
861
+
716
862
  serialize: function(element) {
717
863
  element = $(element);
864
+ var options = Object.extend(Sortable.options(element), arguments[1] || {});
718
865
  var name = encodeURIComponent(
719
866
  (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
720
- return Sortable.sequence(element, arguments[1]).map( function(item) {
721
- return name + "[]=" + encodeURIComponent(item);
722
- }).join('&');
867
+
868
+ if (options.tree) {
869
+ return Sortable.tree(element, arguments[1]).children.map( function (item) {
870
+ return [name + Sortable._constructIndex(item) + "=" +
871
+ encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
872
+ }).flatten().join('&');
873
+ } else {
874
+ return Sortable.sequence(element, arguments[1]).map( function(item) {
875
+ return name + "[]=" + encodeURIComponent(item);
876
+ }).join('&');
877
+ }
723
878
  }
724
879
  }
880
+
881
+ /* Returns true if child is contained within element */
882
+ Element.isParent = function(child, element) {
883
+ if (!child.parentNode || child == element) return false;
884
+
885
+ if (child.parentNode == element) return true;
886
+
887
+ return Element.isParent(child.parentNode, element);
888
+ }
889
+
890
+ Element.findChildren = function(element, only, recursive, tagName) {
891
+ if(!element.hasChildNodes()) return null;
892
+ tagName = tagName.toUpperCase();
893
+ if(only) only = [only].flatten();
894
+ var elements = [];
895
+ $A(element.childNodes).each( function(e) {
896
+ if(e.tagName && e.tagName.toUpperCase()==tagName &&
897
+ (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
898
+ elements.push(e);
899
+ if(recursive) {
900
+ var grandchildren = Element.findChildren(e, only, recursive, tagName);
901
+ if(grandchildren) elements.push(grandchildren);
902
+ }
903
+ });
904
+
905
+ return (elements.length>0 ? elements.flatten() : []);
906
+ }
907
+
908
+ Element.offsetSize = function (element, type) {
909
+ if (type == 'vertical' || type == 'height')
910
+ return element.offsetHeight;
911
+ else
912
+ return element.offsetWidth;
913
+ }