grat 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }