grat 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest CHANGED
@@ -10,8 +10,22 @@ lib/grat/system.rb
10
10
  lib/grat/template.rb
11
11
  public/gratfiles/application.js
12
12
  public/gratfiles/custom.css
13
+ public/gratfiles/einars-js-beautify/HTML-Beautify.js
14
+ public/gratfiles/einars-js-beautify/beautify-cl.js
15
+ public/gratfiles/einars-js-beautify/beautify-tests.js
16
+ public/gratfiles/einars-js-beautify/beautify.js
17
+ public/gratfiles/einars-js-beautify/bin/beautify_js
18
+ public/gratfiles/einars-js-beautify/index.html
19
+ public/gratfiles/einars-js-beautify/javascriptobfuscator_unpacker.js
20
+ public/gratfiles/einars-js-beautify/license.txt
21
+ public/gratfiles/einars-js-beautify/sanitytest.js
22
+ public/gratfiles/einars-js-beautify/unmaintained/bbedit/jsBeautify_BBED.scpt
23
+ public/gratfiles/einars-js-beautify/unmaintained/c-sharp/JSBeautify.cs
24
+ public/gratfiles/einars-js-beautify/unmaintained/opera-userscript/make_opera_userscript.sh
25
+ public/gratfiles/einars-js-beautify/unmaintained/opera-userscript/opera_userscript.js
13
26
  public/gratfiles/favicon.ico
14
27
  public/gratfiles/jquery-combined.min.js
28
+ public/gratfiles/js-beautifier.min.js
15
29
  public/gratfiles/oocss.min.css
16
30
  public/gratfiles/oocss/content.css
17
31
  public/gratfiles/oocss/grids.css
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require 'rubygems'
3
3
  require 'rake'
4
4
  require 'echoe'
5
5
 
6
- Echoe.new('grat', '0.0.1') do |p|
6
+ Echoe.new('grat', '0.0.2') do |p|
7
7
  p.description = "Minimal CMS for Rack and MongoDB."
8
8
  p.url = "http://samsm.com/"
9
9
  p.author = "Sam Schenkman-Moore"
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{grat}
5
- s.version = "0.0.1"
5
+ s.version = "0.0.2"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Sam Schenkman-Moore"]
9
- s.date = %q{2009-10-31}
9
+ s.date = %q{2009-11-01}
10
10
  s.description = %q{Minimal CMS for Rack and MongoDB.}
11
11
  s.email = %q{samsm@samsm.com}
12
12
  s.extra_rdoc_files = ["README", "lib/environment.rb", "lib/grat.rb", "lib/grat/content.rb", "lib/grat/page.rb", "lib/grat/system.rb", "lib/grat/template.rb"]
13
- s.files = ["Manifest", "README", "Rakefile", "config.ru", "lib/environment.rb", "lib/grat.rb", "lib/grat/content.rb", "lib/grat/page.rb", "lib/grat/system.rb", "lib/grat/template.rb", "public/gratfiles/application.js", "public/gratfiles/custom.css", "public/gratfiles/favicon.ico", "public/gratfiles/jquery-combined.min.js", "public/gratfiles/oocss.min.css", "public/gratfiles/oocss/content.css", "public/gratfiles/oocss/grids.css", "public/gratfiles/oocss/grids_debug.css", "public/gratfiles/oocss/libraries.css", "public/gratfiles/oocss/mod.css", "public/gratfiles/oocss/mod_debug.css", "public/gratfiles/oocss/mod_skins.css", "public/gratfiles/oocss/talk.css", "public/gratfiles/oocss/talk_skins.css", "public/gratfiles/oocss/template.css", "public/gratfiles/oocss/template_debug.css", "views/content_form.haml", "views/css/_content.sass", "views/css/_custom.sass", "views/css/_grids.sass", "views/css/_grids_debug.sass", "views/css/_libraries.sass", "views/css/_mod.sass", "views/css/_mod_debug.sass", "views/css/_mod_skins.sass", "views/css/_template.sass", "views/css/_template_debug.sass", "views/layout.haml", "views/list.haml", "views/missing.haml", "grat.gemspec"]
13
+ s.files = ["Manifest", "README", "Rakefile", "config.ru", "lib/environment.rb", "lib/grat.rb", "lib/grat/content.rb", "lib/grat/page.rb", "lib/grat/system.rb", "lib/grat/template.rb", "public/gratfiles/application.js", "public/gratfiles/custom.css", "public/gratfiles/einars-js-beautify/HTML-Beautify.js", "public/gratfiles/einars-js-beautify/beautify-cl.js", "public/gratfiles/einars-js-beautify/beautify-tests.js", "public/gratfiles/einars-js-beautify/beautify.js", "public/gratfiles/einars-js-beautify/bin/beautify_js", "public/gratfiles/einars-js-beautify/index.html", "public/gratfiles/einars-js-beautify/javascriptobfuscator_unpacker.js", "public/gratfiles/einars-js-beautify/license.txt", "public/gratfiles/einars-js-beautify/sanitytest.js", "public/gratfiles/einars-js-beautify/unmaintained/bbedit/jsBeautify_BBED.scpt", "public/gratfiles/einars-js-beautify/unmaintained/c-sharp/JSBeautify.cs", "public/gratfiles/einars-js-beautify/unmaintained/opera-userscript/make_opera_userscript.sh", "public/gratfiles/einars-js-beautify/unmaintained/opera-userscript/opera_userscript.js", "public/gratfiles/favicon.ico", "public/gratfiles/jquery-combined.min.js", "public/gratfiles/js-beautifier.min.js", "public/gratfiles/oocss.min.css", "public/gratfiles/oocss/content.css", "public/gratfiles/oocss/grids.css", "public/gratfiles/oocss/grids_debug.css", "public/gratfiles/oocss/libraries.css", "public/gratfiles/oocss/mod.css", "public/gratfiles/oocss/mod_debug.css", "public/gratfiles/oocss/mod_skins.css", "public/gratfiles/oocss/talk.css", "public/gratfiles/oocss/talk_skins.css", "public/gratfiles/oocss/template.css", "public/gratfiles/oocss/template_debug.css", "views/content_form.haml", "views/css/_content.sass", "views/css/_custom.sass", "views/css/_grids.sass", "views/css/_grids_debug.sass", "views/css/_libraries.sass", "views/css/_mod.sass", "views/css/_mod_debug.sass", "views/css/_mod_skins.sass", "views/css/_template.sass", "views/css/_template_debug.sass", "views/layout.haml", "views/list.haml", "views/missing.haml", "grat.gemspec"]
14
14
  s.homepage = %q{http://samsm.com/}
15
15
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Grat", "--main", "README"]
16
16
  s.require_paths = ["lib"]
@@ -1,7 +1,7 @@
1
1
  require 'sinatra'
2
2
 
3
3
  module Grat
4
-
4
+ @@database_conf = {}
5
5
  def self.root_path
6
6
  File.dirname(File.dirname(__FILE__))
7
7
  end
@@ -35,12 +35,12 @@ class Grat::Application < Sinatra::Base
35
35
 
36
36
  get '/*' do
37
37
  pass if content.new_record?
38
+ locals = {}
38
39
  template_chain.inject('') do |sum, template|
39
- locals ||= {}
40
- locals.merge!(template.attributes)
40
+ locals.merge!(template.default_content_vars.merge(template.attributes))
41
41
  require 'haml'
42
42
  haml_template = Haml::Engine.new(template.content)
43
- haml_template.render(haml_template, locals) { sum }
43
+ result = haml_template.render(haml_template, locals) { sum }
44
44
  end
45
45
  end
46
46
 
@@ -1,13 +1,31 @@
1
1
  module Grat::Content
2
2
 
3
+ def self.included(base)
4
+ base.key :url, String
5
+ base.validates_uniqueness_of :url
6
+ base.key :content, String
7
+ base.key :tags, Array
8
+ base.key :template_url, String
9
+ base.key :variables_needed, Array
10
+ base.timestamps!
11
+
12
+ base.before_save :detect_default_content_vars
13
+ base.key :default_content_vars, Hash
14
+
15
+ base.key :render_engine_name, String
16
+ end
17
+
3
18
  def editable_fields
4
19
  attributes.reject {|k,v| uneditable_keys.include? k }
5
20
  end
6
21
 
7
22
  def uneditable_keys
8
23
  # url is in here so it can maually be placed at the top of edit form.
9
- ["updated_at", "_id", "url", "created_at","content","tags",'template_url','template']
24
+ # Same deal with template_url
25
+ ["updated_at", "_id", "url", "created_at","content","tags",'template_url','template',
26
+ 'default_content_vars','variables_needed','render_engine_name']
10
27
  end
28
+
11
29
  def tags=(val)
12
30
  super(val.kind_of?(Array) ? val : val.split(' '))
13
31
  end
@@ -16,8 +34,84 @@ module Grat::Content
16
34
  self.class.to_s.sub(/.+::/, '')
17
35
  end
18
36
 
37
+ def default_content_vars
38
+ super or {}
39
+ end
40
+
19
41
  def template
20
42
  @template ||= Grat::Template.find_by_url(template_url) if template_url
21
43
  end
22
44
 
45
+ def template=(var)
46
+ raise 'This is probably a mistake.'
47
+ end
48
+
49
+ def template_url=(var)
50
+ super(var) unless var.empty?
51
+ end
52
+
53
+ def demo_string
54
+ 'String needed'
55
+ end
56
+
57
+ def demo_array
58
+ %w(an array is needed)
59
+ end
60
+
61
+ def render_engine
62
+ @render_engine ||= case render_engine_name
63
+ when 'haml',nil # the default for now
64
+ require 'haml'
65
+ Haml::Engine.new(content)
66
+ when 'erb'
67
+ raise 'Unimplemented!'
68
+ end
69
+ end
70
+
71
+ # def detect_variables_needed_by_content
72
+ # demo_variables = {}
73
+ # # formats = [String,Array] # later
74
+ # render_fails = true
75
+ # counter = 0
76
+ # while render_fails
77
+ # counter += 1
78
+ # return false if counter > 200 # no infinite loop, thanks
79
+ # begin
80
+ # content_with(demo_variables)
81
+ # render_fails = false
82
+ # rescue
83
+ # var = $!.to_s.sub(/.+`/,'').sub(/'.+/,'')
84
+ # demo_variables[var] = 'text'
85
+ # end
86
+ # end
87
+ # self.variables_needed = demo_variables.keys
88
+ # end
89
+
90
+ def detect_default_content_vars
91
+ counter = 0
92
+ while problem_var = detect_problem_var
93
+ counter += 1
94
+ return false if counter > 200
95
+ (detect_problem_var(problem_var => demo_string) ||
96
+ default_content_vars.merge!(problem_var => demo_string)) or
97
+ (detect_problem_var(problem_var => demo_array) ||
98
+ default_content_vars.merge!(problem_var => demo_string)) or
99
+ raise "Don't know how to reconcile."
100
+ end
101
+ end
102
+
103
+ def detect_problem_var(resolution = {})
104
+ begin
105
+ rendered = content_with(default_content_vars.merge(resolution), problem_var = nil)
106
+ return false
107
+ rescue
108
+ $!.to_s.sub(/.+`/,'').sub(/'.+/,'')
109
+ end
110
+ end
111
+
112
+ def content_with(locals = {},y = '')
113
+ render_engine.render(render_engine,locals) { y }
114
+ end
115
+
116
+
23
117
  end
@@ -1,13 +1,5 @@
1
1
  class Grat::Page
2
2
  include MongoMapper::Document
3
3
  include Grat::Content
4
-
5
- key :url, String
6
- key :tags, Array
7
- key :content, String
8
- key :template_url, String
9
-
10
- validates_uniqueness_of :url
11
- timestamps!
12
-
4
+
13
5
  end
@@ -4,46 +4,10 @@ class Grat::Template
4
4
 
5
5
  BEGINS_WITH_TEMPLATE = /\A\/templates\/.+/
6
6
 
7
- key :url, String
8
- validates_uniqueness_of :url
9
7
  validates_format_of :url, :with => BEGINS_WITH_TEMPLATE, :message => "needs to begin with '/templates'"
10
-
11
- key :content, String
12
- key :tags, Array
13
- key :template_url, String
14
- key :variables_needed, Array
15
- timestamps!
16
-
17
- # Turn this off for a second
18
- # before_save :detect_variables_needed_by_content
19
-
8
+
20
9
  def url=(val)
21
10
  super(val =~ BEGINS_WITH_TEMPLATE ? val : '/templates/' + val.sub(/\A\//,''))
22
11
  end
23
-
24
- def detect_variables_needed_by_content
25
- haml = Haml::Engine.new(content)
26
- demo_variables = {}
27
- # formats = [String,Array] # later
28
- render_fails = true
29
- counter = 0
30
- while render_fails
31
- counter += 1
32
- return false if counter > 200 # no infinite loop, thanks
33
- begin
34
- content_with(demo_variables)
35
- render_fails = false
36
- rescue
37
- var = $!.to_s.sub(/.+`/,'').sub(/'.+/,'')
38
- demo_variables[var] = 'text'
39
- end
40
- end
41
- self.variables_needed = demo_variables.keys
42
- end
43
-
44
- def content_with(locals = {},y = '')
45
- haml = Haml::Engine.new(content)
46
- haml.render(haml,locals) { y }
47
- end
48
-
12
+
49
13
  end
@@ -1,9 +1,11 @@
1
1
  // once page is loaded ...
2
2
  $(document).ready(function(){
3
+ // New field button + features
3
4
  $('a[href=#new_field]').click(function(){
4
5
 
5
6
  $('#new_fields').prepend("<div class='new_field'><p class='myEditableText sameaslabel'>Write the title here</p><input name='page[new_field]' value='' /></div>");
6
7
 
8
+ // upon click make label editable and other junk associated with customizing the new field
7
9
  $('.myEditableText').click(function(){
8
10
  editable = $(this);
9
11
 
@@ -56,11 +58,16 @@ $(document).ready(function(){
56
58
  // user saves changed content
57
59
  $('.editableText').change(function(){
58
60
  var newValue = $(this).html();
59
-
60
61
  });
61
62
 
62
63
 
63
64
 
64
65
  return false;
65
66
  })
67
+
68
+ // Beautify default data textarea
69
+ $('#default_content_vars').each(function() {
70
+ this.innerHTML = js_beautify(this.innerHTML, {'indent_size':2});
71
+ })
72
+
66
73
  });
@@ -0,0 +1,427 @@
1
+ /*
2
+
3
+ Style HTML
4
+ ---------------
5
+
6
+ Written by Nochum Sossonko, (nsossonko@hotmail.com)
7
+
8
+ Based on code initially developed by: Einar Lielmanis, <elfz@laacz.lv>
9
+ http://jsbeautifier.org
10
+
11
+
12
+ You are free to use this in any way you want, in case you find this useful or working for you.
13
+
14
+ Usage:
15
+ style_html(html_source);
16
+
17
+ */
18
+
19
+ function style_html(html_source, indent_size, indent_character, max_char) {
20
+ //Wrapper function to invoke all the necessary constructors and deal with the output.
21
+
22
+ var Parser, multi_parser;
23
+
24
+ function Parser() {
25
+
26
+ this.pos = 0; //Parser position
27
+ this.token = '';
28
+ this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT
29
+ this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values
30
+ parent: 'parent1',
31
+ parentcount: 1,
32
+ parent1: ''
33
+ };
34
+ this.tag_type = '';
35
+ this.token_text = this.last_token = this.last_text = this.token_type = '';
36
+
37
+
38
+ this.Utils = { //Uilities made available to the various functions
39
+ whitespace: "\n\r\t ".split(''),
40
+ single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed'.split(','), //all the single tags for HTML
41
+ extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them
42
+ in_array: function (what, arr) {
43
+ for (var i=0; i<arr.length; i++) {
44
+ if (what === arr[i]) {
45
+ return true;
46
+ }
47
+ }
48
+ return false;
49
+ }
50
+ }
51
+
52
+ this.get_content = function () { //function to capture regular content between tags
53
+
54
+ var input_char = '';
55
+ var content = [];
56
+ var space = false; //if a space is needed
57
+ while (this.input.charAt(this.pos) !== '<') {
58
+ if (this.pos >= this.input.length) {
59
+ return content.length?content.join(''):['', 'TK_EOF'];
60
+ }
61
+
62
+ input_char = this.input.charAt(this.pos);
63
+ this.pos++;
64
+ this.line_char_count++;
65
+
66
+
67
+ if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
68
+ if (content.length) {
69
+ space = true;
70
+ }
71
+ this.line_char_count--;
72
+ continue; //don't want to insert unnecessary space
73
+ }
74
+ else if (space) {
75
+ if (this.line_char_count >= this.max_char) { //insert a line when the max_char is reached
76
+ content.push('\n');
77
+ for (var i=0; i<this.indent_level; i++) {
78
+ content.push(this.indent_string);
79
+ }
80
+ this.line_char_count = 0;
81
+ }
82
+ else{
83
+ content.push(' ');
84
+ this.line_char_count++;
85
+ }
86
+ space = false;
87
+ }
88
+ content.push(input_char); //letter at-a-time (or string) inserted to an array
89
+ }
90
+ return content.length?content.join(''):'';
91
+ }
92
+
93
+ this.get_script = function () { //get the full content of a script to pass to js_beautify
94
+
95
+ var input_char = '';
96
+ var content = [];
97
+ var reg_match = new RegExp('\<\/script' + '\>', 'igm');
98
+ reg_match.lastIndex = this.pos;
99
+ var reg_array = reg_match.exec(this.input);
100
+ var end_script = reg_array?reg_array.index:this.input.length; //absolute end of script
101
+ while(this.pos < end_script) { //get everything in between the script tags
102
+ if (this.pos >= this.input.length) {
103
+ return content.length?content.join(''):['', 'TK_EOF'];
104
+ }
105
+
106
+ input_char = this.input.charAt(this.pos);
107
+ this.pos++;
108
+
109
+
110
+ content.push(input_char);
111
+ }
112
+ return content.length?content.join(''):''; //we might not have any content at all
113
+ }
114
+
115
+ this.record_tag = function (tag){ //function to record a tag and its parent in this.tags Object
116
+ if (this.tags[tag + 'count']) { //check for the existence of this tag type
117
+ this.tags[tag + 'count']++;
118
+ this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
119
+ }
120
+ else { //otherwise initialize this tag type
121
+ this.tags[tag + 'count'] = 1;
122
+ this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
123
+ }
124
+ this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; //set the parent (i.e. in the case of a div this.tags.div1parent)
125
+ this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1')
126
+ }
127
+
128
+ this.retrieve_tag = function (tag) { //function to retrieve the opening tag to the corresponding closer
129
+ if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it
130
+ var temp_parent = this.tags.parent; //check to see if it's a closable tag.
131
+ while (temp_parent) { //till we reach '' (the initial value);
132
+ if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it
133
+ break;
134
+ }
135
+ temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree
136
+ }
137
+ if (temp_parent) { //if we caught something
138
+ this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly
139
+ this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent
140
+ }
141
+ delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference...
142
+ delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself
143
+ if (this.tags[tag + 'count'] == 1) {
144
+ delete this.tags[tag + 'count'];
145
+ }
146
+ else {
147
+ this.tags[tag + 'count']--;
148
+ }
149
+ }
150
+ }
151
+
152
+ this.get_tag = function () { //function to get a full tag and parse its type
153
+ var input_char = '';
154
+ var content = [];
155
+ var space = false;
156
+
157
+ do {
158
+ if (this.pos >= this.input.length) {
159
+ return content.length?content.join(''):['', 'TK_EOF'];
160
+ }
161
+
162
+ input_char = this.input.charAt(this.pos);
163
+ this.pos++;
164
+ this.line_char_count++;
165
+
166
+ if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space
167
+ space = true;
168
+ this.line_char_count--;
169
+ continue;
170
+ }
171
+
172
+ if (input_char === "'" || input_char === '"') {
173
+ if (!content[1] || content[1] !== '!') { //if we're in a comment strings don't get treated specially
174
+ input_char += this.get_unformatted(input_char);
175
+ space = true;
176
+ }
177
+ }
178
+
179
+ if (input_char === '=') { //no space before =
180
+ space = false;
181
+ }
182
+
183
+ if (content.length && content[content.length-1] !== '=' && input_char !== '>'
184
+ && space) { //no space after = or before >
185
+ if (this.line_char_count >= this.max_char) {
186
+ this.print_newline(false, content);
187
+ this.line_char_count = 0;
188
+ }
189
+ else {
190
+ content.push(' ');
191
+ this.line_char_count++;
192
+ }
193
+ space = false;
194
+ }
195
+ content.push(input_char); //inserts character at-a-time (or string)
196
+ } while (input_char !== '>');
197
+
198
+ var tag_complete = content.join('');
199
+ var tag_index;
200
+ if (tag_complete.indexOf(' ') != -1) { //if there's whitespace, thats where the tag name ends
201
+ tag_index = tag_complete.indexOf(' ');
202
+ }
203
+ else { //otherwise go with the tag ending
204
+ tag_index = tag_complete.indexOf('>');
205
+ }
206
+ var tag_check = tag_complete.substring(1, tag_index).toLowerCase();
207
+ if (tag_complete.charAt(tag_complete.length-2) === '/' ||
208
+ this.Utils.in_array(tag_check, this.Utils.single_token)) { //if this tag name is a single tag type (either in the list or has a closing /)
209
+ this.tag_type = 'SINGLE';
210
+ }
211
+ else if (tag_check === 'script') { //for later script handling
212
+ this.record_tag(tag_check);
213
+ this.tag_type = 'SCRIPT';
214
+ }
215
+ else if (tag_check === 'style') { //for future style handling (for now it justs uses get_content)
216
+ this.record_tag(tag_check);
217
+ this.tag_type = 'STYLE';
218
+ }
219
+ else if (tag_check.charAt(0) === '!') { //peek for <!-- comment
220
+ if (tag_check.indexOf('[if') != -1) { //peek for <!--[if conditional comment
221
+ if (tag_complete.indexOf('!IE') != -1) { //this type needs a closing --> so...
222
+ var comment = this.get_unformatted('-->', tag_complete); //...delegate to get_unformatted
223
+ content.push(comment);
224
+ }
225
+ this.tag_type = 'START';
226
+ }
227
+ else if (tag_check.indexOf('[endif') != -1) {//peek for <!--[endif end conditional comment
228
+ this.tag_type = 'END';
229
+ this.unindent();
230
+ }
231
+ else if (tag_check.indexOf('[cdata[') != -1) { //if it's a <[cdata[ comment...
232
+ var comment = this.get_unformatted(']]>', tag_complete); //...delegate to get_unformatted function
233
+ content.push(comment);
234
+ this.tag_type = 'SINGLE'; //<![CDATA[ comments are treated like single tags
235
+ }
236
+ else {
237
+ var comment = this.get_unformatted('-->', tag_complete);
238
+ content.push(comment);
239
+ this.tag_type = 'SINGLE';
240
+ }
241
+ }
242
+ else {
243
+ if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending
244
+ this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors
245
+ this.tag_type = 'END';
246
+ }
247
+ else { //otherwise it's a start-tag
248
+ this.record_tag(tag_check); //push it on the tag stack
249
+ this.tag_type = 'START';
250
+ }
251
+ if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line
252
+ this.print_newline(true, this.output);
253
+ }
254
+ }
255
+ return content.join(''); //returns fully formatted tag
256
+ }
257
+
258
+ this.get_unformatted = function (delimiter, orig_tag) { //function to return unformatted content in its entirety
259
+
260
+ if (orig_tag && orig_tag.indexOf(delimiter) != -1) {
261
+ return '';
262
+ }
263
+ var input_char = '';
264
+ var content = '';
265
+ var space = true;
266
+ do {
267
+
268
+
269
+ input_char = this.input.charAt(this.pos);
270
+ this.pos++
271
+
272
+ if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
273
+ if (!space) {
274
+ this.line_char_count--;
275
+ continue;
276
+ }
277
+ if (input_char === '\n' || input_char === '\r') {
278
+ content += '\n';
279
+ for (var i=0; i<this.indent_level; i++) {
280
+ content += this.indent_string;
281
+ }
282
+ space = false; //...and make sure other indentation is erased
283
+ this.line_char_count = 0;
284
+ continue;
285
+ }
286
+ }
287
+ content += input_char;
288
+ this.line_char_count++;
289
+ space = true;
290
+
291
+
292
+ } while (content.indexOf(delimiter) == -1);
293
+ return content;
294
+ }
295
+
296
+ this.get_token = function () { //initial handler for token-retrieval
297
+ var token;
298
+
299
+ if (this.last_token === 'TK_TAG_SCRIPT') { //check if we need to format javascript
300
+ var temp_token = this.get_script();
301
+ if (typeof temp_token !== 'string') {
302
+ return temp_token;
303
+ }
304
+ token = js_beautify(temp_token,
305
+ {indent_size: this.indent_size, indent_char: this.indent_character, indent_level: this.indent_level}); //call the JS Beautifier
306
+ return [token, 'TK_CONTENT'];
307
+ }
308
+ if (this.current_mode === 'CONTENT') {
309
+ token = this.get_content();
310
+ if (typeof token !== 'string') {
311
+ return token;
312
+ }
313
+ else {
314
+ return [token, 'TK_CONTENT'];
315
+ }
316
+ }
317
+
318
+ if(this.current_mode === 'TAG') {
319
+ token = this.get_tag();
320
+ if (typeof token !== 'string') {
321
+ return token;
322
+ }
323
+ else {
324
+ var tag_name_type = 'TK_TAG_' + this.tag_type;
325
+ return [token, tag_name_type];
326
+ }
327
+ }
328
+ }
329
+
330
+ this.printer = function (js_source, indent_character, indent_size, max_char) { //handles input/output and some other printing functions
331
+
332
+ this.input = js_source || ''; //gets the input for the Parser
333
+ this.output = [];
334
+ this.indent_character = indent_character || ' ';
335
+ this.indent_string = '';
336
+ this.indent_size = indent_size || 2;
337
+ this.indent_level = 0;
338
+ this.max_char = max_char || 70; //maximum amount of characters per line
339
+ this.line_char_count = 0; //count to see if max_char was exceeded
340
+
341
+ for (var i=0; i<this.indent_size; i++) {
342
+ this.indent_string += this.indent_character;
343
+ }
344
+
345
+ this.print_newline = function (ignore, arr) {
346
+ this.line_char_count = 0;
347
+ if (!arr || !arr.length) {
348
+ return;
349
+ }
350
+ if (!ignore) { //we might want the extra line
351
+ while (this.Utils.in_array(arr[arr.length-1], this.Utils.whitespace)) {
352
+ arr.pop();
353
+ }
354
+ }
355
+ arr.push('\n');
356
+ for (var i=0; i<this.indent_level; i++) {
357
+ arr.push(this.indent_string);
358
+ }
359
+ }
360
+
361
+
362
+ this.print_token = function (text) {
363
+ this.output.push(text);
364
+ }
365
+
366
+ this.indent = function () {
367
+ this.indent_level++;
368
+ }
369
+
370
+ this.unindent = function () {
371
+ if (this.indent_level > 0) {
372
+ this.indent_level--;
373
+ }
374
+ }
375
+ }
376
+ return this;
377
+ }
378
+
379
+ /*_____________________--------------------_____________________*/
380
+
381
+
382
+
383
+ multi_parser = new Parser(); //wrapping functions Parser
384
+ multi_parser.printer(html_source, indent_character, indent_size); //initialize starting values
385
+
386
+
387
+
388
+ while (true) {
389
+ var t = multi_parser.get_token();
390
+ multi_parser.token_text = t[0];
391
+ multi_parser.token_type = t[1];
392
+
393
+ if (multi_parser.token_type === 'TK_EOF') {
394
+ break;
395
+ }
396
+
397
+
398
+ switch (multi_parser.token_type) {
399
+ case 'TK_TAG_START': case 'TK_TAG_SCRIPT': case 'TK_TAG_STYLE':
400
+ multi_parser.print_newline(false, multi_parser.output);
401
+ multi_parser.print_token(multi_parser.token_text);
402
+ multi_parser.indent();
403
+ multi_parser.current_mode = 'CONTENT';
404
+ break;
405
+ case 'TK_TAG_END':
406
+ multi_parser.print_newline(true, multi_parser.output);
407
+ multi_parser.print_token(multi_parser.token_text);
408
+ multi_parser.current_mode = 'CONTENT';
409
+ break;
410
+ case 'TK_TAG_SINGLE':
411
+ multi_parser.print_newline(false, multi_parser.output);
412
+ multi_parser.print_token(multi_parser.token_text);
413
+ multi_parser.current_mode = 'CONTENT';
414
+ break;
415
+ case 'TK_CONTENT':
416
+ if (multi_parser.token_text !== '') {
417
+ multi_parser.print_newline(false, multi_parser.output);
418
+ multi_parser.print_token(multi_parser.token_text);
419
+ }
420
+ multi_parser.current_mode = 'TAG';
421
+ break;
422
+ }
423
+ multi_parser.last_token = multi_parser.token_type;
424
+ multi_parser.last_text = multi_parser.token_text;
425
+ }
426
+ return multi_parser.output.join('');
427
+ }