feather_cms 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/README.md +46 -0
  4. data/Rakefile +1 -0
  5. data/feather_cms.gemspec +24 -0
  6. data/lib/feather_cms/config.rb +54 -0
  7. data/lib/feather_cms/model.rb +59 -0
  8. data/lib/feather_cms/railtie.rb +13 -0
  9. data/lib/feather_cms/template_cache.rb +52 -0
  10. data/lib/feather_cms/version.rb +3 -0
  11. data/lib/feather_cms/view_helper.rb +20 -0
  12. data/lib/feather_cms.rb +19 -0
  13. data/lib/generators/feather_cms/USAGE +10 -0
  14. data/lib/generators/feather_cms/feather_cms_generator.rb +63 -0
  15. data/lib/generators/feather_cms/templates/bootstrap.css +3992 -0
  16. data/lib/generators/feather_cms/templates/codemirror/codemirror.css +117 -0
  17. data/lib/generators/feather_cms/templates/codemirror/codemirror.js +2909 -0
  18. data/lib/generators/feather_cms/templates/codemirror/feather_cms.js +13 -0
  19. data/lib/generators/feather_cms/templates/codemirror/modes/css.js +124 -0
  20. data/lib/generators/feather_cms/templates/codemirror/modes/htmlmixed.js +83 -0
  21. data/lib/generators/feather_cms/templates/codemirror/modes/javascript.js +360 -0
  22. data/lib/generators/feather_cms/templates/codemirror/modes/xml.js +267 -0
  23. data/lib/generators/feather_cms/templates/codemirror/util/dialog.css +23 -0
  24. data/lib/generators/feather_cms/templates/codemirror/util/dialog.js +63 -0
  25. data/lib/generators/feather_cms/templates/codemirror/util/foldcode.js +186 -0
  26. data/lib/generators/feather_cms/templates/codemirror/util/formatting.js +294 -0
  27. data/lib/generators/feather_cms/templates/codemirror/util/javascript-hint.js +134 -0
  28. data/lib/generators/feather_cms/templates/codemirror/util/match-highlighter.js +44 -0
  29. data/lib/generators/feather_cms/templates/codemirror/util/overlay.js +51 -0
  30. data/lib/generators/feather_cms/templates/codemirror/util/runmode.js +49 -0
  31. data/lib/generators/feather_cms/templates/codemirror/util/search.js +114 -0
  32. data/lib/generators/feather_cms/templates/codemirror/util/searchcursor.js +117 -0
  33. data/lib/generators/feather_cms/templates/codemirror/util/simple-hint.css +16 -0
  34. data/lib/generators/feather_cms/templates/codemirror/util/simple-hint.js +68 -0
  35. data/lib/generators/feather_cms/templates/controller.rb +34 -0
  36. data/lib/generators/feather_cms/templates/form.html.erb +40 -0
  37. data/lib/generators/feather_cms/templates/index.html.erb +11 -0
  38. data/lib/generators/feather_cms/templates/initializer.rb +5 -0
  39. data/lib/generators/feather_cms/templates/layout.html.erb +52 -0
  40. data/lib/generators/feather_cms/templates/migration.rb +13 -0
  41. data/lib/generators/feather_cms/templates/model.rb +3 -0
  42. metadata +98 -0
@@ -0,0 +1,117 @@
1
+ (function(){
2
+ function SearchCursor(cm, query, pos, caseFold) {
3
+ this.atOccurrence = false; this.cm = cm;
4
+ if (caseFold == null) caseFold = typeof query == "string" && query == query.toLowerCase();
5
+
6
+ pos = pos ? cm.clipPos(pos) : {line: 0, ch: 0};
7
+ this.pos = {from: pos, to: pos};
8
+
9
+ // The matches method is filled in based on the type of query.
10
+ // It takes a position and a direction, and returns an object
11
+ // describing the next occurrence of the query, or null if no
12
+ // more matches were found.
13
+ if (typeof query != "string") // Regexp match
14
+ this.matches = function(reverse, pos) {
15
+ if (reverse) {
16
+ var line = cm.getLine(pos.line).slice(0, pos.ch), match = line.match(query), start = 0;
17
+ while (match) {
18
+ var ind = line.indexOf(match[0]);
19
+ start += ind;
20
+ line = line.slice(ind + 1);
21
+ var newmatch = line.match(query);
22
+ if (newmatch) match = newmatch;
23
+ else break;
24
+ start++;
25
+ }
26
+ }
27
+ else {
28
+ var line = cm.getLine(pos.line).slice(pos.ch), match = line.match(query),
29
+ start = match && pos.ch + line.indexOf(match[0]);
30
+ }
31
+ if (match)
32
+ return {from: {line: pos.line, ch: start},
33
+ to: {line: pos.line, ch: start + match[0].length},
34
+ match: match};
35
+ };
36
+ else { // String query
37
+ if (caseFold) query = query.toLowerCase();
38
+ var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
39
+ var target = query.split("\n");
40
+ // Different methods for single-line and multi-line queries
41
+ if (target.length == 1)
42
+ this.matches = function(reverse, pos) {
43
+ var line = fold(cm.getLine(pos.line)), len = query.length, match;
44
+ if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
45
+ : (match = line.indexOf(query, pos.ch)) != -1)
46
+ return {from: {line: pos.line, ch: match},
47
+ to: {line: pos.line, ch: match + len}};
48
+ };
49
+ else
50
+ this.matches = function(reverse, pos) {
51
+ var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(cm.getLine(ln));
52
+ var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
53
+ if (reverse ? offsetA >= pos.ch || offsetA != match.length
54
+ : offsetA <= pos.ch || offsetA != line.length - match.length)
55
+ return;
56
+ for (;;) {
57
+ if (reverse ? !ln : ln == cm.lineCount() - 1) return;
58
+ line = fold(cm.getLine(ln += reverse ? -1 : 1));
59
+ match = target[reverse ? --idx : ++idx];
60
+ if (idx > 0 && idx < target.length - 1) {
61
+ if (line != match) return;
62
+ else continue;
63
+ }
64
+ var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
65
+ if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
66
+ return;
67
+ var start = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB};
68
+ return {from: reverse ? end : start, to: reverse ? start : end};
69
+ }
70
+ };
71
+ }
72
+ }
73
+
74
+ SearchCursor.prototype = {
75
+ findNext: function() {return this.find(false);},
76
+ findPrevious: function() {return this.find(true);},
77
+
78
+ find: function(reverse) {
79
+ var self = this, pos = this.cm.clipPos(reverse ? this.pos.from : this.pos.to);
80
+ function savePosAndFail(line) {
81
+ var pos = {line: line, ch: 0};
82
+ self.pos = {from: pos, to: pos};
83
+ self.atOccurrence = false;
84
+ return false;
85
+ }
86
+
87
+ for (;;) {
88
+ if (this.pos = this.matches(reverse, pos)) {
89
+ this.atOccurrence = true;
90
+ return this.pos.match || true;
91
+ }
92
+ if (reverse) {
93
+ if (!pos.line) return savePosAndFail(0);
94
+ pos = {line: pos.line-1, ch: this.cm.getLine(pos.line-1).length};
95
+ }
96
+ else {
97
+ var maxLine = this.cm.lineCount();
98
+ if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
99
+ pos = {line: pos.line+1, ch: 0};
100
+ }
101
+ }
102
+ },
103
+
104
+ from: function() {if (this.atOccurrence) return this.pos.from;},
105
+ to: function() {if (this.atOccurrence) return this.pos.to;},
106
+
107
+ replace: function(newText) {
108
+ var self = this;
109
+ if (this.atOccurrence)
110
+ self.pos.to = this.cm.replaceRange(newText, self.pos.from, self.pos.to);
111
+ }
112
+ };
113
+
114
+ CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
115
+ return new SearchCursor(this, query, pos, caseFold);
116
+ });
117
+ })();
@@ -0,0 +1,16 @@
1
+ .CodeMirror-completions {
2
+ position: absolute;
3
+ z-index: 10;
4
+ overflow: hidden;
5
+ -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
6
+ -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
7
+ box-shadow: 2px 3px 5px rgba(0,0,0,.2);
8
+ }
9
+ .CodeMirror-completions select {
10
+ background: #fafafa;
11
+ outline: none;
12
+ border: none;
13
+ padding: 0;
14
+ margin: 0;
15
+ font-family: monospace;
16
+ }
@@ -0,0 +1,68 @@
1
+ (function() {
2
+ CodeMirror.simpleHint = function(editor, getHints) {
3
+ // We want a single cursor position.
4
+ if (editor.somethingSelected()) return;
5
+ var result = getHints(editor);
6
+ if (!result || !result.list.length) return;
7
+ var completions = result.list;
8
+ function insert(str) {
9
+ editor.replaceRange(str, result.from, result.to);
10
+ }
11
+ // When there is only one completion, use it directly.
12
+ if (completions.length == 1) {insert(completions[0]); return true;}
13
+
14
+ // Build the select widget
15
+ var complete = document.createElement("div");
16
+ complete.className = "CodeMirror-completions";
17
+ var sel = complete.appendChild(document.createElement("select"));
18
+ // Opera doesn't move the selection when pressing up/down in a
19
+ // multi-select, but it does properly support the size property on
20
+ // single-selects, so no multi-select is necessary.
21
+ if (!window.opera) sel.multiple = true;
22
+ for (var i = 0; i < completions.length; ++i) {
23
+ var opt = sel.appendChild(document.createElement("option"));
24
+ opt.appendChild(document.createTextNode(completions[i]));
25
+ }
26
+ sel.firstChild.selected = true;
27
+ sel.size = Math.min(10, completions.length);
28
+ var pos = editor.cursorCoords();
29
+ complete.style.left = pos.x + "px";
30
+ complete.style.top = pos.yBot + "px";
31
+ document.body.appendChild(complete);
32
+ // Hack to hide the scrollbar.
33
+ if (completions.length <= 10)
34
+ complete.style.width = (sel.clientWidth - 1) + "px";
35
+
36
+ var done = false;
37
+ function close() {
38
+ if (done) return;
39
+ done = true;
40
+ complete.parentNode.removeChild(complete);
41
+ }
42
+ function pick() {
43
+ insert(completions[sel.selectedIndex]);
44
+ close();
45
+ setTimeout(function(){editor.focus();}, 50);
46
+ }
47
+ CodeMirror.connect(sel, "blur", close);
48
+ CodeMirror.connect(sel, "keydown", function(event) {
49
+ var code = event.keyCode;
50
+ // Enter
51
+ if (code == 13) {CodeMirror.e_stop(event); pick();}
52
+ // Escape
53
+ else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();}
54
+ else if (code != 38 && code != 40) {
55
+ close(); editor.focus();
56
+ // Pass the event to the CodeMirror instance so that it can handle things like backspace properly.
57
+ editor.triggerOnKeyDown(event);
58
+ setTimeout(function(){CodeMirror.simpleHint(editor, getHints);}, 50);
59
+ }
60
+ });
61
+ CodeMirror.connect(sel, "dblclick", pick);
62
+
63
+ sel.focus();
64
+ // Opera sometimes ignores focusing a freshly created node
65
+ if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100);
66
+ return true;
67
+ };
68
+ })();
@@ -0,0 +1,34 @@
1
+ class FeathersController < ApplicationController
2
+ http_basic_authenticate_with name: 'feather', password: 'password', except: :published
3
+ before_filter :find_page, only: [:page, :preivew]
4
+
5
+ layout 'feather_layout', except: [:preivew, :published]
6
+
7
+ def index
8
+ @pages = FeatherPage.all
9
+ end
10
+
11
+ def page
12
+ if request.put? or request.post?
13
+ @feather_page.attributes = params[:feather_page]
14
+ @feather_page.name = params[:type]
15
+ @feather_page.save
16
+ end
17
+ render action: @feather_page.name
18
+ end
19
+
20
+ def preivew
21
+ render inline: @feather_page.content, type: 'html', layout: @feather_page.layout
22
+ end
23
+
24
+ def published
25
+ @feather_page = FeatherPage.where(name: params[:type], status: 'published').first
26
+ render inline: @feather_page.content, type: 'html', layout: @feather_page.layout
27
+ end
28
+
29
+ def find_page
30
+ status = params[:feather_page] ? params[:feather_page][:status] : (params[:status] || 'draft')
31
+ @feather_page = FeatherPage.where(name: params[:type], status: status)
32
+ @feather_page = @feather_page.first || @feather_page.new
33
+ end
34
+ end
@@ -0,0 +1,40 @@
1
+ <header>
2
+ <%% status = params[:status] || @feather_page.status %>
3
+ <div class="subnav">
4
+ <ul class="nav nav-pills">
5
+ <li class='<%%= status == 'published' ? 'active ' : '' %>'>
6
+ <%%= link_to 'Published Page', feather_page_path('<%= @type %>',:published) %>
7
+ </li>
8
+ <li class='<%%= status == 'draft' ? 'active ' : '' %>'>
9
+ <%%= link_to 'Draft Page', feather_page_path('<%= @type %>', :draft) %>
10
+ </li>
11
+ <li>
12
+ <%%= link_to 'Preview', feather_page_preview_path('<%= @type %>', status), target: '_blank' %>
13
+ </li>
14
+ </ul>
15
+ </div>
16
+ <hr>
17
+ </header>
18
+ <div class="row">
19
+ <div class="span12">
20
+ <%%= form_for(@feather_page, :url => feather_page_path('<%= @type %>')) do |f| %>
21
+ <div class="control-group">
22
+ <label class="control-label" for="status">Status</label>
23
+ <div class="controls">
24
+ <%%= f.select :status, [:draft, :published] %>
25
+ </div>
26
+ <label class="control-label" for="layout">Layout</label>
27
+ <div class="controls">
28
+ <%%= f.select :layout, FeatherCms::Config.layouts %>
29
+ </div>
30
+ </div>
31
+ <div class="control-group">
32
+ <label class="control-label" for="textarea">Content</label>
33
+ <div class="controls">
34
+ <%%= f.text_area :content, :class => 'codemirror_feather_cms input-xlarge span12', :row => "20" %>
35
+ </div>
36
+ </div>
37
+ <%%= f.submit "Save", :class => 'btn btn-primary btn-large' %>
38
+ <%% end %>
39
+ </div>
40
+ </div>
@@ -0,0 +1,11 @@
1
+ <div class="row">
2
+ <ol>
3
+ <%% @pages.each do |page| %>
4
+ <li>
5
+ <strong>
6
+ <%%= link_to "#{page.name.humanize}(#{page.status})", feather_page_path(page.name, page.status) %>
7
+ </strong>
8
+ </li>
9
+ <%% end %>
10
+ </ol>
11
+ </div>
@@ -0,0 +1,5 @@
1
+ FeatherCms::Config.init do |c|
2
+ c.template_store_path = 'public/system/templates'
3
+ c.template_store_type = :<%= @storage %>
4
+ #c.template_extenstion = 'html' #default : html
5
+ end
@@ -0,0 +1,52 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Feather CMS</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <meta name="description" content="">
8
+ <meta name="author" content="">
9
+
10
+ <!-- Le styles -->
11
+ <%%= stylesheet_link_tag 'bootstrap' %>
12
+ <%%= javascript_include_tag 'jquery' %>
13
+ <%%= feather_cms_include_tag %>
14
+ <style type="text/css">
15
+ body {
16
+ padding-top: 60px;
17
+ padding-bottom: 40px;
18
+ }
19
+ </style>
20
+
21
+ <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
22
+ <!--[if lt IE 9]>
23
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
24
+ <![endif]-->
25
+
26
+ </head>
27
+
28
+ <body>
29
+
30
+ <div class="navbar navbar-fixed-top">
31
+ <div class="navbar-inner">
32
+ <div class="container">
33
+ <%%= link_to 'Feather CMS', feather_pages_path, :class => 'brand' %>
34
+ <div class="nav-collapse">
35
+ <ul class="nav">
36
+ <%- @pages.each do |page| -%>
37
+ <li class="<%%= params[:type] == '<%=page%>' ? 'active' : '' %>">
38
+ <%%= link_to '<%= page.humanize %>' , feather_page_path('<%= page %>') %>
39
+ </li>
40
+ <%- end -%>
41
+ </ul>
42
+ </div><!--/.nav-collapse -->
43
+ </div>
44
+ </div>
45
+ </div>
46
+
47
+ <div class="container">
48
+ <%%= yield %>
49
+ </div>
50
+
51
+ </body>
52
+ </html>
@@ -0,0 +1,13 @@
1
+ class CreateFeatherPages < ActiveRecord::Migration
2
+ def change
3
+ create_table :feather_pages do |t|
4
+ t.string :name
5
+ t.string :status, :default => 'draft'
6
+ <% if @storaage == 'db' %>
7
+ t.text :content
8
+ <% end %>
9
+ t.string :layout, :default => 'application'
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ class FeatherPage < ActiveRecord::Base
2
+ include FeatherCms
3
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: feather_cms
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jiren Patel
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-30 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &9554190 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *9554190
25
+ description: Lightweight do it youself cms
26
+ email:
27
+ - jiren@joshsoftware.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - .gitignore
33
+ - Gemfile
34
+ - README.md
35
+ - Rakefile
36
+ - feather_cms.gemspec
37
+ - lib/feather_cms.rb
38
+ - lib/feather_cms/config.rb
39
+ - lib/feather_cms/model.rb
40
+ - lib/feather_cms/railtie.rb
41
+ - lib/feather_cms/template_cache.rb
42
+ - lib/feather_cms/version.rb
43
+ - lib/feather_cms/view_helper.rb
44
+ - lib/generators/feather_cms/USAGE
45
+ - lib/generators/feather_cms/feather_cms_generator.rb
46
+ - lib/generators/feather_cms/templates/bootstrap.css
47
+ - lib/generators/feather_cms/templates/codemirror/codemirror.css
48
+ - lib/generators/feather_cms/templates/codemirror/codemirror.js
49
+ - lib/generators/feather_cms/templates/codemirror/feather_cms.js
50
+ - lib/generators/feather_cms/templates/codemirror/modes/css.js
51
+ - lib/generators/feather_cms/templates/codemirror/modes/htmlmixed.js
52
+ - lib/generators/feather_cms/templates/codemirror/modes/javascript.js
53
+ - lib/generators/feather_cms/templates/codemirror/modes/xml.js
54
+ - lib/generators/feather_cms/templates/codemirror/util/dialog.css
55
+ - lib/generators/feather_cms/templates/codemirror/util/dialog.js
56
+ - lib/generators/feather_cms/templates/codemirror/util/foldcode.js
57
+ - lib/generators/feather_cms/templates/codemirror/util/formatting.js
58
+ - lib/generators/feather_cms/templates/codemirror/util/javascript-hint.js
59
+ - lib/generators/feather_cms/templates/codemirror/util/match-highlighter.js
60
+ - lib/generators/feather_cms/templates/codemirror/util/overlay.js
61
+ - lib/generators/feather_cms/templates/codemirror/util/runmode.js
62
+ - lib/generators/feather_cms/templates/codemirror/util/search.js
63
+ - lib/generators/feather_cms/templates/codemirror/util/searchcursor.js
64
+ - lib/generators/feather_cms/templates/codemirror/util/simple-hint.css
65
+ - lib/generators/feather_cms/templates/codemirror/util/simple-hint.js
66
+ - lib/generators/feather_cms/templates/controller.rb
67
+ - lib/generators/feather_cms/templates/form.html.erb
68
+ - lib/generators/feather_cms/templates/index.html.erb
69
+ - lib/generators/feather_cms/templates/initializer.rb
70
+ - lib/generators/feather_cms/templates/layout.html.erb
71
+ - lib/generators/feather_cms/templates/migration.rb
72
+ - lib/generators/feather_cms/templates/model.rb
73
+ homepage: ''
74
+ licenses: []
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project: feather_cms
93
+ rubygems_version: 1.8.10
94
+ signing_key:
95
+ specification_version: 3
96
+ summary: Lightweight do it youself cms
97
+ test_files: []
98
+ has_rdoc: