liquid_cms 0.3.0.8 → 0.3.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG.rdoc +7 -0
  3. data/TODO.rdoc +1 -1
  4. data/app/controllers/cms/main_controller.rb +3 -2
  5. data/app/helpers/cms/common_helper.rb +9 -2
  6. data/app/helpers/cms/components_helper.rb +10 -4
  7. data/app/liquid/filters/cms_filters.rb +1 -0
  8. data/app/models/cms/component.rb +4 -0
  9. data/app/views/cms/assets/_list.html.erb +4 -4
  10. data/app/views/cms/components/_list.html.erb +5 -1
  11. data/app/views/cms/components/edit.html.erb +1 -1
  12. data/app/views/cms/pages/_list.html.erb +4 -4
  13. data/app/views/cms/shared/_sidebar.html.erb +31 -8
  14. data/app/views/layouts/cms.html.erb +5 -2
  15. data/config/initializers/cms/simple_form_updates.rb +2 -2
  16. data/config/locales/cms/en.yml +3 -2
  17. data/lib/generators/liquid_cms/templates/public/cms/codemirror/LICENSE +0 -0
  18. data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/csscolors.css +0 -0
  19. data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/docs.css +17 -3
  20. data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/font.js +15 -0
  21. data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/jscolors.css +0 -0
  22. data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/sparqlcolors.css +0 -0
  23. data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/xmlcolors.css +0 -0
  24. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/codemirror.js +59 -26
  25. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/editor.js +149 -71
  26. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/highlight.js +2 -2
  27. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/mirrorframe.js +2 -2
  28. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsecss.js +5 -3
  29. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsedummy.js +0 -0
  30. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsehtmlmixed.js +28 -9
  31. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsejavascript.js +0 -0
  32. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsesparql.js +0 -0
  33. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsexml.js +6 -1
  34. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/select.js +48 -21
  35. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/stringstream.js +15 -1
  36. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/tokenize.js +0 -0
  37. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/tokenizejavascript.js +1 -1
  38. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/undo.js +17 -14
  39. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/unittests.js +44 -0
  40. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/util.js +6 -3
  41. data/lib/generators/liquid_cms/templates/public/cms/javascripts/cms.js +15 -1
  42. data/lib/generators/liquid_cms/templates/public/cms/javascripts/livepipe.js +181 -0
  43. data/lib/generators/liquid_cms/templates/public/cms/javascripts/tabs.js +149 -0
  44. data/lib/generators/liquid_cms/templates/public/cms/stylesheets/ie9.css +4 -0
  45. data/lib/generators/liquid_cms/templates/public/cms/stylesheets/sidebar.css +132 -0
  46. data/lib/generators/liquid_cms/templates/public/cms/stylesheets/styles.css +1 -74
  47. data/lib/generators/liquid_cms/templates/public/cms/stylesheets/themes/dark.css +2 -1
  48. data/lib/liquid_cms/context.rb +4 -0
  49. data/lib/liquid_cms/version.rb +1 -1
  50. data/liquid_cms.gemspec +1 -1
  51. data/test/rails_app/Gemfile +1 -2
  52. data/test/rails_app/Gemfile.lock +56 -62
  53. metadata +24 -16
  54. data/Gemfile.lock +0 -122
  55. data/lib/generators/liquid_cms/templates/public/cms/codemirror/bigtest.html +0 -1296
  56. data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/people.jpg +0 -0
  57. data/lib/generators/liquid_cms/templates/public/cms/codemirror/csstest.html +0 -60
  58. data/lib/generators/liquid_cms/templates/public/cms/codemirror/highlight.html +0 -82
  59. data/lib/generators/liquid_cms/templates/public/cms/codemirror/htmltest.html +0 -52
  60. data/lib/generators/liquid_cms/templates/public/cms/codemirror/index.html +0 -245
  61. data/lib/generators/liquid_cms/templates/public/cms/codemirror/jstest.html +0 -56
  62. data/lib/generators/liquid_cms/templates/public/cms/codemirror/manual.html +0 -759
  63. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mixedtest.html +0 -52
  64. data/lib/generators/liquid_cms/templates/public/cms/codemirror/sparqltest.html +0 -41
  65. data/lib/generators/liquid_cms/templates/public/cms/codemirror/story.html +0 -671
data/.gitignore CHANGED
@@ -3,4 +3,5 @@ pkg/*
3
3
  *.swp
4
4
  .bundle
5
5
  .rvmrc
6
+ Gemfile.lock
6
7
  test/rails_app/log
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,10 @@
1
+ == 0.3.0.9
2
+
3
+ * Enhancements
4
+ * Upgrade codemirror syntax highlighting to 0.94
5
+ * Remember component folders view state.
6
+ * Add tabs for each resource type.
7
+
1
8
  == 0.3.0.8
2
9
 
3
10
  * Enhancements
data/TODO.rdoc CHANGED
@@ -3,6 +3,6 @@
3
3
  * No functions are currently limited to specific user roles. All CMS users can perform the same actions.
4
4
  * Implement caching and expiration logic.
5
5
  * Provide example apache/nginx/etc. conf files that properly scope cms assets for each context.
6
- * Generate CMS documentation from rdoc comments in source files.
6
+ * Generate CMS documentation from rdoc comments in source files?
7
7
  * Search functions. Find templates based on search text.
8
8
  * Missing tests... add more coverage.
@@ -5,7 +5,7 @@ class Cms::MainController < Cms::SetupController
5
5
 
6
6
  unloadable
7
7
 
8
- before_filter :load_pages_and_assets
8
+ before_filter :load_resources
9
9
 
10
10
  authenticate_user :all, :only => %w(index)
11
11
 
@@ -14,10 +14,11 @@ class Cms::MainController < Cms::SetupController
14
14
  end
15
15
 
16
16
  protected
17
- def load_pages_and_assets
17
+ def load_resources
18
18
  @context = Cms::Context.new(@cms_context)
19
19
 
20
20
  @pages = @context.pages.ordered.all(:conditions => {:layout_page_id => nil})
21
21
  @assets = @context.assets.ordered
22
+ @components = @context.components
22
23
  end
23
24
  end
@@ -1,4 +1,12 @@
1
1
  module Cms::CommonHelper
2
+ # js cookie accessor
3
+ def cookie_jar(key)
4
+ # if the cookie hasn't been set, need to return '{}' to return a proper hash
5
+ # and if the cookie has been set, but is 'null', we need to then return a ruby hash
6
+ # __CJ_ is the cookiejar js lib postfix value for cookies
7
+ ActiveSupport::JSON.decode(cookies["__CJ_#{key}".to_sym] || '{}') || {}
8
+ end
9
+
2
10
  def cms_icon(name, options = {})
3
11
  image_tag "/cms/images/icons/#{name}", options.merge(:size => '16x16')
4
12
  end
@@ -95,7 +103,6 @@ module Cms::CommonHelper
95
103
  end
96
104
 
97
105
  def asset_preview_option
98
- # __CJ_ is the cookiejar js lib postfix value for cookies
99
- ActiveSupport::JSON.decode(cookies[:__CJ_toggle] || '{}')['on'] == false ? 'style="display:none"' : ''
106
+ cookie_jar('toggle')['on'] == false ? 'style="display:none"' : ''
100
107
  end
101
108
  end
@@ -1,4 +1,8 @@
1
1
  module Cms::ComponentsHelper
2
+ def component_folder_open?(folder_id)
3
+ cookie_jar('component_folders')[folder_id].present?
4
+ end
5
+
2
6
  def component_edit_link(path)
3
7
  full_path = Cms::Component.component_path(@context, path)
4
8
  link_to(truncate(File.basename(path), :length => 15), {:controller => 'cms/components', :action => 'edit', :url => CGI::escape(full_path)})
@@ -9,15 +13,17 @@ module Cms::ComponentsHelper
9
13
  link_to(cms_icon('delete.png', :title => 'Delete'), {:controller => 'cms/components', :action => 'destroy', :url => CGI::escape(full_path)}, :confirm => "Are you sure you want to remove '#{full_path}'?")
10
14
  end
11
15
 
12
- def list_files(path, hidden = false)
16
+ def list_files(files, hidden = false)
13
17
  html = ''
14
18
  html += hidden ? %[<ul class="tree" style="display:none">] : %[<ul class="tree">]
15
- for file in Dir[File.expand_path(path)+"/*"] do
19
+ for file in files do
16
20
  html += "<li>"
17
21
  if File.directory?(file)
18
- html += cms_icon('folder.png', :class => 'folder') + ' ' + component_delete_link(file) + ' '
22
+ folder_id = "folder_#{Digest::MD5.hexdigest(file)}"
23
+
24
+ html += cms_icon('folder.png', :class => 'folder', :id => folder_id) + ' ' + component_delete_link(file) + ' '
19
25
  html += content_tag(:span, File.basename(file), :title => Cms::Component.component_path(@context, file))
20
- html += list_files(file, true)
26
+ html += list_files(Cms::Component.files(file), !component_folder_open?(folder_id))
21
27
  else
22
28
  html += file_type_icon(File.basename(file)) + ' '
23
29
  html += component_delete_link(file) + ' '
@@ -1,4 +1,5 @@
1
1
  require 'formatize/helper'
2
+ require 'will_paginate'
2
3
 
3
4
  class Module
4
5
  # for the tezeilze method to work
@@ -21,6 +21,10 @@ class Cms::Component
21
21
  path.sub(full_path(context).to_s + "/", '')
22
22
  end
23
23
 
24
+ def self.files(path)
25
+ Dir[File.expand_path(path) + "/*"]
26
+ end
27
+
24
28
  def self.valid_type?(file)
25
29
  %w(.css .js .png .jpg .jpeg .gif .json .xml .fla .ico).include?(File.extname(file).downcase)
26
30
  end
@@ -1,4 +1,8 @@
1
1
  <div id="assets">
2
+ <p>
3
+ <%= cms_icon 'picture_add.png' %> <%= link_to t('assets.actions.index.new_link'), new_cms_asset_path %>
4
+ </p>
5
+
2
6
  <% if @assets.empty? %>
3
7
  <p><%= t 'assets.actions.index.none' %></p>
4
8
  <% else %>
@@ -7,8 +11,4 @@
7
11
  <%= render :partial => 'cms/assets/asset', :collection => @assets %>
8
12
  </ul>
9
13
  <% end %>
10
-
11
- <p>
12
- <%= cms_icon 'picture_add.png' %> <%= link_to t('assets.actions.index.new_link'), new_cms_asset_path %>
13
- </p>
14
14
  </div>
@@ -4,5 +4,9 @@
4
4
  <%= submit_tag 'Upload' %> <em>.zip files only</em>
5
5
  <% end %>
6
6
 
7
- <%= list_files Cms::Component.full_path(@context) %>
7
+ <% if @components.empty? %>
8
+ <p><%= t 'components.actions.index.none' %></p>
9
+ <% else %>
10
+ <%= list_files @components %>
11
+ <% end %>
8
12
  </div>
@@ -1,6 +1,6 @@
1
1
  <h2>Edit Component File</h2>
2
2
 
3
- <% form_tag({:controller => 'cms/components', :action => 'update', :url => CGI::escape(@component.path)}, :class => 'simple_form') do %>
3
+ <%= form_tag({:controller => 'cms/components', :action => 'update', :url => CGI::escape(@component.path)}, :class => 'simple_form') do %>
4
4
  <div class="string required">
5
5
  <%= label_tag :name, nil, :class => 'string required' %> <%= text_field_tag :name, @component.path, :readonly => true, :class => 'string required' %>
6
6
  </div>
@@ -1,4 +1,8 @@
1
1
  <div id="pages">
2
+ <p>
3
+ <%= cms_icon 'page_add.png' %> <%= link_to t('pages.actions.index.new_link'), new_cms_page_path %>
4
+ </p>
5
+
2
6
  <% if @pages.empty? %>
3
7
  <p><%= t 'pages.actions.index.none' %></p>
4
8
  <% else %>
@@ -6,8 +10,4 @@
6
10
  <%= render :partial => 'cms/pages/page', :collection => @pages %>
7
11
  </ul>
8
12
  <% end %>
9
-
10
- <p>
11
- <%= cms_icon 'page_add.png' %> <%= link_to t('pages.actions.index.new_link'), new_cms_page_path %>
12
- </p>
13
13
  </div>
@@ -1,11 +1,34 @@
1
- <h2><%= t 'pages.actions.index.title' %></h2>
2
- <%= render 'cms/pages/list' %>
1
+ <ul id="cms_menus" class="tabs clearfix">
2
+ <li><%= link_to t('pages.actions.index.title'), '#cms_pages' %></li>
3
+ <li><%= link_to t('assets.actions.index.title'), '#cms_assets' %></li>
4
+ <li><%= link_to t('components.actions.index.title'), '#cms_components' %></li>
5
+ </ul>
3
6
 
4
- <h2><%= t 'assets.actions.index.title' %></h2>
5
- <%= render 'cms/assets/list' %>
7
+ <div id="tab_container">
8
+ <div id="cms_pages">
9
+ <h2><%= t 'pages.actions.index.title' %></h2>
10
+ <%= render 'cms/pages/list' %>
11
+ </div>
6
12
 
7
- <h2><%= t 'components.actions.index.title' %></h2>
8
- <%= render 'cms/components/list' %>
13
+ <div id="cms_assets">
14
+ <h2><%= t 'assets.actions.index.title' %></h2>
15
+ <%= render 'cms/assets/list' %>
16
+ </div>
9
17
 
10
- <hr style="border:1px solid #BBB" />
11
- <p style="text-align:right"><%= cms_icon 'page.png' %> <%= link_to 'Documentation', cms_documentation_index_path %></p>
18
+ <div id="cms_components">
19
+ <h2><%= t 'components.actions.index.title' %></h2>
20
+ <%= render 'cms/components/list' %>
21
+ </div>
22
+ </div>
23
+
24
+ <%= javascript_tag do %>
25
+ new Control.Tabs('cms_menus', {
26
+ defaultTab: jar.get('active_tab') || 'first',
27
+ afterChange: function(new_container) {
28
+ // save the active tab
29
+ jar.put('active_tab', new_container.getAttribute('id'));
30
+ }
31
+ });
32
+ <% end %>
33
+
34
+ <p class="documentation"><%= cms_icon 'page.png' %> <%= link_to 'Documentation', cms_documentation_index_path %></p>
@@ -5,15 +5,18 @@
5
5
  <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
6
6
  <title>Liquid CMS</title>
7
7
  <%= javascript_include_tag 'prototype', 'effects', 'rails' %>
8
- <%= javascript_include_tag '/cms/javascripts/humanmsg', '/cms/javascripts/cookiejar', '/cms/javascripts/remote_helpers', '/cms/javascripts/cms' %>
8
+ <%= javascript_include_tag '/cms/javascripts/humanmsg', '/cms/javascripts/cookiejar', '/cms/javascripts/remote_helpers', '/cms/javascripts/cms', '/cms/javascripts/livepipe', '/cms/javascripts/tabs', :cache => 'cms_scripts' %>
9
9
  <%= javascript_include_tag '/cms/codemirror/js/codemirror' %>
10
10
  <%= stylesheet_link_tag '/cms/stylesheets/simple_form' %>
11
- <%= stylesheet_link_tag '/cms/stylesheets/clearfix', '/cms/stylesheets/humanmsg', '/cms/stylesheets/styles' %>
11
+ <%= stylesheet_link_tag '/cms/stylesheets/clearfix', '/cms/stylesheets/humanmsg', '/cms/stylesheets/styles', '/cms/stylesheets/sidebar', :cache => 'cms_styles' %>
12
12
  <%= stylesheet_link_tag '/cms/stylesheets/themes/dark' %>
13
13
  <%= yield :cms_styles %>
14
14
  <!--[if lte IE 8]>
15
15
  <%= stylesheet_link_tag '/cms/stylesheets/ie' %>
16
16
  <![endif]-->
17
+ <!--[if lte IE 9]>
18
+ <%= stylesheet_link_tag '/cms/stylesheets/ie9' %>
19
+ <![endif]-->
17
20
  <%= csrf_meta_tag %>
18
21
  </head>
19
22
  <body id="cms" class="cms_<%= params[:controller].camelize.demodulize.downcase %>">
@@ -1,10 +1,10 @@
1
1
  class SimpleForm::FormBuilder
2
2
  def commit_button_or_cancel
3
- @template.content_tag :div, :class => 'buttons' do
3
+ template.content_tag :div, :class => 'buttons' do
4
4
  String.new.tap do |html|
5
5
  html << button(:submit)
6
6
  html << " or "
7
- html << template.link_to(@template.t('simple_form.buttons.cancel'), :back, :class => 'cancel')
7
+ html << template.link_to(template.t('simple_form.buttons.cancel'), :back, :class => 'cancel')
8
8
  end.html_safe
9
9
  end
10
10
  end
@@ -2,7 +2,7 @@ en:
2
2
  pages:
3
3
  actions:
4
4
  index:
5
- title: 'Site Pages'
5
+ title: 'Pages'
6
6
  none: 'There are currently no pages.'
7
7
  new_link: 'Create a new page'
8
8
  new:
@@ -17,7 +17,7 @@ en:
17
17
  assets:
18
18
  actions:
19
19
  index:
20
- title: 'Site Assets'
20
+ title: 'Assets'
21
21
  none: 'There are currently no assets.'
22
22
  new_link: 'Upload a new asset'
23
23
  new:
@@ -33,6 +33,7 @@ en:
33
33
  actions:
34
34
  index:
35
35
  title: 'Components'
36
+ none: 'There are currently no components.'
36
37
 
37
38
  simple_form:
38
39
  "yes": 'Yes'
@@ -1,10 +1,13 @@
1
1
  body {
2
- font-family: Droid Sans, Arial, sans-serif;
2
+ font-family: Arial, sans-serif;
3
3
  line-height: 1.5;
4
4
  max-width: 64.3em;
5
5
  margin: 3em auto;
6
6
  padding: 0 1em;
7
7
  }
8
+ body.droid {
9
+ font-family: Droid Sans, Arial, sans-serif;
10
+ }
8
11
 
9
12
  h1 {
10
13
  letter-spacing: -3px;
@@ -27,7 +30,7 @@ h3 {
27
30
  }
28
31
 
29
32
  pre {
30
- font-family: Droid Sans Mono, Courier New, monospaced;
33
+ font-family: Courier New, monospaced;
31
34
  background-color: #eee;
32
35
  -moz-border-radius: 6px;
33
36
  -webkit-border-radius: 6px;
@@ -44,6 +47,13 @@ pre.code {
44
47
  padding: .5em 1em;
45
48
  line-height: 1.2em;
46
49
  margin-top: .5em;
50
+ position: relative;
51
+ }
52
+
53
+ img.logo {
54
+ position: absolute;
55
+ right: -25px;
56
+ bottom: 4px;
47
57
  }
48
58
 
49
59
  a:link, a:visited, .quasilink {
@@ -52,10 +62,14 @@ a:link, a:visited, .quasilink {
52
62
  text-decoration: none;
53
63
  }
54
64
 
55
- a:hover {
65
+ a:hover, .quasilink:hover {
56
66
  color: #800004;
57
67
  }
58
68
 
69
+ h1 a:link, h1 a:visited, h1 a:hover {
70
+ color: black;
71
+ }
72
+
59
73
  ul {
60
74
  margin: 0;
61
75
  padding-left: 1.2em;
@@ -0,0 +1,15 @@
1
+ function waitForStyles() {
2
+ for (var i = 0; i < document.styleSheets.length; i++)
3
+ if (/googleapis/.test(document.styleSheets[i].href))
4
+ return document.body.className += " droid";
5
+ setTimeout(waitForStyles, 100);
6
+ }
7
+ setTimeout(function() {
8
+ if (/AppleWebKit/.test(navigator.userAgent) && /iP[oa]d|iPhone/.test(navigator.userAgent)) return;
9
+ var link = document.createElement("LINK");
10
+ link.type = "text/css";
11
+ link.rel = "stylesheet";
12
+ link.href = "http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans:bold";
13
+ document.documentElement.getElementsByTagName("HEAD")[0].appendChild(link);
14
+ waitForStyles();
15
+ }, 20);
@@ -21,6 +21,12 @@ var CodeMirror = (function(){
21
21
  for (var i = 0; i < array.length; i++)
22
22
  action(array[i]);
23
23
  }
24
+ function createHTMLElement(el) {
25
+ if (document.createElementNS && document.documentElement.namespaceURI !== null)
26
+ return document.createElementNS("http://www.w3.org/1999/xhtml", el)
27
+ else
28
+ return document.createElement(el)
29
+ }
24
30
 
25
31
  // These default options can be overridden by passing a set of
26
32
  // options to a specific CodeMirror constructor. See manual.html for
@@ -37,6 +43,7 @@ var CodeMirror = (function(){
37
43
  lineNumberTime: 50,
38
44
  continuousScanning: false,
39
45
  saveFunction: null,
46
+ onLoad: null,
40
47
  onChange: null,
41
48
  undoDepth: 50,
42
49
  undoDelay: 800,
@@ -47,22 +54,27 @@ var CodeMirror = (function(){
47
54
  height: "300px",
48
55
  minHeight: 100,
49
56
  autoMatchParens: false,
57
+ markParen: null,
58
+ unmarkParen: null,
50
59
  parserConfig: null,
51
60
  tabMode: "indent", // or "spaces", "default", "shift"
52
61
  enterMode: "indent", // or "keep", "flat"
53
62
  electricChars: true,
54
63
  reindentOnLoad: false,
55
64
  activeTokens: null,
56
- cursorActivity: null,
65
+ onCursorActivity: null,
57
66
  lineNumbers: false,
58
67
  firstLineNumber: 1,
68
+ onLineNumberClick: null,
59
69
  indentUnit: 2,
60
- domain: null
70
+ domain: null,
71
+ noScriptCaching: false,
72
+ incrementalLoading: false
61
73
  });
62
74
 
63
75
  function addLineNumberDiv(container, firstNum) {
64
- var nums = document.createElement("DIV"),
65
- scroller = document.createElement("DIV");
76
+ var nums = createHTMLElement("div"),
77
+ scroller = createHTMLElement("div");
66
78
  nums.style.position = "absolute";
67
79
  nums.style.height = "100%";
68
80
  if (nums.style.setExpression) {
@@ -87,18 +99,19 @@ var CodeMirror = (function(){
87
99
  if (typeof options.stylesheet == "string")
88
100
  options.stylesheet = [options.stylesheet];
89
101
 
90
- var html = ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"><html><head>"];
102
+ var sp = " spellcheck=\"" + (options.disableSpellcheck ? "false" : "true") + "\"";
103
+ var html = ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"><html" + sp + "><head>"];
91
104
  // Hack to work around a bunch of IE8-specific problems.
92
105
  html.push("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=EmulateIE7\"/>");
106
+ var queryStr = options.noScriptCaching ? "?nocache=" + new Date().getTime().toString(16) : "";
93
107
  forEach(options.stylesheet, function(file) {
94
- html.push("<link rel=\"stylesheet\" type=\"text/css\" href=\"" + file + "\"/>");
108
+ html.push("<link rel=\"stylesheet\" type=\"text/css\" href=\"" + file + queryStr + "\"/>");
95
109
  });
96
110
  forEach(options.basefiles.concat(options.parserfile), function(file) {
97
111
  if (!/^https?:/.test(file)) file = options.path + file;
98
- html.push("<script type=\"text/javascript\" src=\"" + file + "\"><" + "/script>");
112
+ html.push("<script type=\"text/javascript\" src=\"" + file + queryStr + "\"><" + "/script>");
99
113
  });
100
- html.push("</head><body style=\"border-width: 0;\" class=\"editbox\" spellcheck=\"" +
101
- (options.disableSpellcheck ? "false" : "true") + "\"></body></html>");
114
+ html.push("</head><body style=\"border-width: 0;\" class=\"editbox\"" + sp + "></body></html>");
102
115
  return html.join("");
103
116
  }
104
117
 
@@ -112,8 +125,9 @@ var CodeMirror = (function(){
112
125
  // Backward compatibility for deprecated options.
113
126
  if (options.dumbTabs) options.tabMode = "spaces";
114
127
  else if (options.normalTab) options.tabMode = "default";
128
+ if (options.cursorActivity) options.onCursorActivity = options.cursorActivity;
115
129
 
116
- var frame = this.frame = document.createElement("IFRAME");
130
+ var frame = this.frame = createHTMLElement("iframe");
117
131
  if (options.iframeClass) frame.className = options.iframeClass;
118
132
  frame.frameBorder = 0;
119
133
  frame.style.border = "0";
@@ -123,17 +137,18 @@ var CodeMirror = (function(){
123
137
  // always add it, redundant as it sounds.
124
138
  frame.style.display = "block";
125
139
 
126
- var div = this.wrapping = document.createElement("DIV");
140
+ var div = this.wrapping = createHTMLElement("div");
127
141
  div.style.position = "relative";
128
142
  div.className = "CodeMirror-wrapping";
129
143
  div.style.width = options.width;
130
144
  div.style.height = (options.height == "dynamic") ? options.minHeight + "px" : options.height;
131
145
  // This is used by Editor.reroutePasteEvent
132
- var teHack = this.textareaHack = document.createElement("TEXTAREA");
146
+ var teHack = this.textareaHack = createHTMLElement("textarea");
133
147
  div.appendChild(teHack);
134
148
  teHack.style.position = "absolute";
135
149
  teHack.style.left = "-10000px";
136
150
  teHack.style.width = "10px";
151
+ teHack.tabIndex = 100000;
137
152
 
138
153
  // Link back to this object, so that the editor can fetch options
139
154
  // and add a reference to itself.
@@ -163,7 +178,9 @@ var CodeMirror = (function(){
163
178
 
164
179
  CodeMirror.prototype = {
165
180
  init: function() {
181
+ // Deprecated, but still supported.
166
182
  if (this.options.initCallback) this.options.initCallback(this);
183
+ if (this.options.onLoad) this.options.onLoad(this);
167
184
  if (this.options.lineNumbers) this.activateLineNumbers();
168
185
  if (this.options.reindentOnLoad) this.reindent();
169
186
  if (this.options.height == "dynamic") this.setDynamicHeight();
@@ -177,7 +194,8 @@ var CodeMirror = (function(){
177
194
 
178
195
  focusIfIE: function() {
179
196
  // in IE, a lot of selection-related functionality only works when the frame is focused
180
- if (this.win.select.ie_selection) this.focus();
197
+ if (this.win.select.ie_selection && document.activeElement != this.frame)
198
+ this.focus();
181
199
  },
182
200
  focus: function() {
183
201
  this.win.focus();
@@ -257,12 +275,12 @@ var CodeMirror = (function(){
257
275
  setEnterMode: function(mode) {this.options.enterMode = mode;},
258
276
  setLineNumbers: function(on) {
259
277
  if (on && !this.lineNumbers) {
260
- this.lineNumbers = addLineNumberDiv(this.wrapping);
278
+ this.lineNumbers = addLineNumberDiv(this.wrapping,this.options.firstLineNumber);
261
279
  this.activateLineNumbers();
262
280
  }
263
281
  else if (!on && this.lineNumbers) {
264
282
  this.wrapping.removeChild(this.lineNumbers);
265
- this.wrapping.style.marginLeft = "";
283
+ this.wrapping.style.paddingLeft = "";
266
284
  this.lineNumbers = null;
267
285
  }
268
286
  },
@@ -312,6 +330,15 @@ var CodeMirror = (function(){
312
330
  nums = this.lineNumbers, scroller = nums.firstChild, self = this;
313
331
  var barWidth = null;
314
332
 
333
+ nums.onclick = function(e) {
334
+ var handler = self.options.onLineNumberClick;
335
+ if (handler) {
336
+ var div = (e || window.event).target || (e || window.event).srcElement;
337
+ var num = div == nums ? NaN : Number(div.innerHTML);
338
+ if (!isNaN(num)) handler(num, div);
339
+ }
340
+ };
341
+
315
342
  function sizeBar() {
316
343
  if (frame.offsetWidth == 0) return;
317
344
  for (var root = frame; root.parentNode; root = root.parentNode){}
@@ -341,7 +368,7 @@ var CodeMirror = (function(){
341
368
  var targetHeight = 50 + Math.max(body.offsetHeight, Math.max(frame.offsetHeight, body.scrollHeight || 0)),
342
369
  lastNumber = Math.ceil(targetHeight / lineHeight);
343
370
  for (var i = scroller.childNodes.length; i <= lastNumber; i++) {
344
- var div = document.createElement("DIV");
371
+ var div = createHTMLElement("div");
345
372
  div.appendChild(document.createTextNode(fill ? String(i + self.options.firstLineNumber) : "\u00a0"));
346
373
  scroller.appendChild(div);
347
374
  }
@@ -368,7 +395,7 @@ var CodeMirror = (function(){
368
395
  function setNum(n, node) {
369
396
  // Does not typically happen (but can, if you mess with the
370
397
  // document during the numbering)
371
- if (!lineNum) lineNum = scroller.appendChild(document.createElement("DIV"));
398
+ if (!lineNum) lineNum = scroller.appendChild(createHTMLElement("div"));
372
399
  if (styleNums) styleNums(lineNum, node, n);
373
400
  // Changes are accumulated, so that the document layout
374
401
  // doesn't have to be recomputed during the pass
@@ -389,7 +416,11 @@ var CodeMirror = (function(){
389
416
  setNum(next++, node.previousSibling);
390
417
  for (; node && !win.isBR(node); node = node.nextSibling) {
391
418
  var bott = node.offsetTop + node.offsetHeight;
392
- while (scroller.offsetHeight && bott - 3 > pos) setNum("&nbsp;");
419
+ while (scroller.offsetHeight && bott - 3 > pos) {
420
+ var oldPos = pos;
421
+ setNum("&nbsp;");
422
+ if (pos <= oldPos) break;
423
+ }
393
424
  }
394
425
  if (node) node = node.nextSibling;
395
426
  if (new Date().getTime() > endTime) {
@@ -433,7 +464,7 @@ var CodeMirror = (function(){
433
464
  },
434
465
 
435
466
  setDynamicHeight: function() {
436
- var self = this, activity = self.options.cursorActivity, win = self.win, body = win.document.body,
467
+ var self = this, activity = self.options.onCursorActivity, win = self.win, body = win.document.body,
437
468
  lineHeight = null, timeout = null, vmargin = 2 * self.frame.offsetTop;
438
469
  body.style.overflowY = "hidden";
439
470
  win.document.documentElement.style.overflowY = "hidden";
@@ -456,7 +487,7 @@ var CodeMirror = (function(){
456
487
  self.wrapping.style.height = Math.max(vmargin + computedHeight, self.options.minHeight) + "px";
457
488
  }
458
489
  setTimeout(updateHeight, 300);
459
- self.options.cursorActivity = function(x) {
490
+ self.options.onCursorActivity = function(x) {
460
491
  if (activity) activity(x);
461
492
  clearTimeout(timeout);
462
493
  timeout = setTimeout(updateHeight, 100);
@@ -485,10 +516,10 @@ var CodeMirror = (function(){
485
516
  options.height = area.style.height;
486
517
  if (options.content == null) options.content = area.value;
487
518
 
519
+ function updateField() {
520
+ area.value = mirror.getCode();
521
+ }
488
522
  if (area.form) {
489
- function updateField() {
490
- area.value = mirror.getCode();
491
- }
492
523
  if (typeof area.form.addEventListener == "function")
493
524
  area.form.addEventListener("submit", updateField, false);
494
525
  else
@@ -501,7 +532,7 @@ var CodeMirror = (function(){
501
532
  area.form.submit();
502
533
  area.form.submit = wrapSubmit;
503
534
  }
504
- area.form.submit = wrapSubmit;
535
+ try {area.form.submit = wrapSubmit;} catch(e){}
505
536
  }
506
537
 
507
538
  function insert(frame) {
@@ -513,11 +544,13 @@ var CodeMirror = (function(){
513
544
 
514
545
  area.style.display = "none";
515
546
  var mirror = new CodeMirror(insert, options);
547
+ mirror.save = updateField;
516
548
  mirror.toTextArea = function() {
549
+ updateField();
517
550
  area.parentNode.removeChild(mirror.wrapping);
518
551
  area.style.display = "";
519
552
  if (area.form) {
520
- area.form.submit = realSubmit;
553
+ try {area.form.submit = realSubmit;} catch(e) {}
521
554
  if (typeof area.form.removeEventListener == "function")
522
555
  area.form.removeEventListener("submit", updateField, false);
523
556
  else
@@ -533,7 +566,7 @@ var CodeMirror = (function(){
533
566
  var match;
534
567
  if (window.opera)
535
568
  return Number(window.opera.version()) >= 9.52;
536
- else if (/Apple Computers, Inc/.test(navigator.vendor) && (match = navigator.userAgent.match(/Version\/(\d+(?:\.\d+)?)\./)))
569
+ else if (/Apple Computer, Inc/.test(navigator.vendor) && (match = navigator.userAgent.match(/Version\/(\d+(?:\.\d+)?)\./)))
537
570
  return Number(match[1]) >= 3;
538
571
  else if (document.selection && window.ActiveXObject && (match = navigator.userAgent.match(/MSIE (\d+(?:\.\d*)?)\b/)))
539
572
  return Number(match[1]) >= 6;