i0n_rails3_generators 0.2.17 → 0.2.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (20) hide show
  1. data/config/version.yml +1 -1
  2. data/lib/generators/i0n/layout/layout_generator.rb +23 -8
  3. data/lib/generators/i0n/layout/templates/app/views/layouts/application.haml +4 -4
  4. data/lib/generators/i0n/layout/templates/config/assets.yml +25 -0
  5. data/lib/generators/i0n/layout/templates/public/javascripts/application.js +8 -0
  6. data/lib/generators/i0n/layout/templates/public/javascripts/lib/client.js +12 -0
  7. data/lib/generators/i0n/layout/templates/public/javascripts/lib/create_html5_elements.js +6 -0
  8. data/lib/generators/i0n/layout/templates/public/javascripts/lib/rails.js +132 -0
  9. data/lib/generators/i0n/layout/templates/public/javascripts/vendor/IE9.js +6 -0
  10. data/lib/generators/i0n/layout/templates/public/javascripts/vendor/backbone.0.3.3.js +1012 -0
  11. data/lib/generators/i0n/layout/templates/public/javascripts/vendor/jquery.1.5.2.js +8374 -0
  12. data/lib/generators/i0n/layout/templates/public/javascripts/vendor/jquery.form.2.4.9.js +785 -0
  13. data/lib/generators/i0n/layout/templates/public/javascripts/vendor/jquery.remotipart.js +52 -0
  14. data/lib/generators/i0n/layout/templates/public/javascripts/vendor/jquery.uploadProgress.js +116 -0
  15. data/lib/generators/i0n/layout/templates/public/javascripts/vendor/json2.js +481 -0
  16. data/lib/generators/i0n/layout/templates/public/javascripts/vendor/underscore.1.1.5.js +796 -0
  17. data/lib/generators/i0n/layout/templates/public/javascripts/views/index.js +0 -0
  18. data/lib/generators/i0n/layout/templates/public/javascripts/views/new.js +0 -0
  19. data/lib/generators/i0n/layout/templates/public/javascripts/views/show.js +0 -0
  20. metadata +18 -2
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :version_major: 0
3
3
  :version_minor: 2
4
- :version_patch: 17
4
+ :version_patch: 18
@@ -5,16 +5,30 @@ module I0n
5
5
  source_root File.expand_path('../templates', __FILE__)
6
6
 
7
7
  def gemfile
8
+ # Memcached
9
+ gem 'dalli'
10
+
11
+ # Data storage
12
+ gem 'bson_ext'
13
+ gem 'mongoid'
14
+
15
+ # File uplaod
16
+ gem 'carrierwave'
17
+ gem 'mini_magick'
18
+
8
19
  # File minification
9
- gem 'smurf'
20
+ gem 'jammit'
21
+
10
22
  # Templates
11
23
  gem 'haml'
12
- gem 'haml-rails'
24
+ gem 'haml-rails'
25
+
26
+ # jQuery
27
+ gem 'jquery-rails'
28
+
13
29
  # Stylesheets
14
30
  gem "compass"
15
31
  gem 'compass-susy-plugin'
16
- # JavaScript
17
- gem 'jquery-rails'
18
32
  end
19
33
 
20
34
  def setup_application
@@ -41,6 +55,11 @@ end
41
55
  directory "app/sass", "#{Rails.root}/app/sass"
42
56
  end
43
57
 
58
+ def create_jammit_assets
59
+ copy_file "config/assets.yml", "#{Rails.root}/config/assets.yml"
60
+ directory "public/javascripts", "#{Rails.root}/public/javascripts"
61
+ end
62
+
44
63
  def create_layout
45
64
  copy_file "app/views/layouts/application.haml", "#{Rails.root}/app/views/layouts/application.haml"
46
65
  copy_file "app/views/shared/_error_messages.haml", "#{Rails.root}/app/views/shared/_error_messages.haml"
@@ -50,10 +69,6 @@ end
50
69
  remove_file "app/views/layouts/application.html.erb"
51
70
  end
52
71
 
53
- def generate_jquery
54
- generate("jquery:install")
55
- end
56
-
57
72
  end
58
73
  end
59
74
  end
@@ -6,11 +6,11 @@
6
6
  = csrf_meta_tag
7
7
  %title
8
8
  #{yield :title}
9
- = stylesheet_link_tag 'screen.css', :media => 'screen, projection'
9
+ = include_stylesheets :screen, :media => 'all'
10
10
  /[if IE 7]
11
- = stylesheet_link_tag 'ie', :media => 'screen, projection'
11
+ = include_stylesheets :ie, :media => 'screen, projection', :embed_images => false
12
12
  /[if lt IE 9]
13
- %script{ :src => "http://ie7-js.googlecode.com/svn/version/2.1(beta4)/IE9.js" }
13
+ = include_javascripts :ie
14
14
  %body
15
15
  .container
16
16
  %header
@@ -35,7 +35,7 @@
35
35
  .container
36
36
  .container{:class => "sub_footer"}
37
37
  %p © #{Time.now.year}
38
- = javascript_include_tag :defaults
38
+ = include_javascripts :workspace
39
39
  :javascript
40
40
  var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
41
41
  document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
@@ -0,0 +1,25 @@
1
+ embed_assets: datauri
2
+
3
+ javascripts:
4
+ ie:
5
+ - public/javascripts/lib/create_html5_elements.js
6
+ workspace:
7
+ - public/javascripts/vendor/jquery.1.5.2.js
8
+ - public/javascripts/vendor/json2.js
9
+ - public/javascripts/vendor/underscore.1.1.5.js
10
+ - public/javascripts/vendor/backbone.0.3.3.js
11
+ - public/javascripts/vendor/jquery.form.2.4.9.js
12
+ - public/javascripts/vendor/jquery.remotipart.js
13
+ - public/javascripts/vendor/jquery.uploadProgress.js
14
+ - public/javascripts/application.js
15
+ - public/javascripts/models/*.js
16
+ - public/javascripts/**/*.js
17
+ - app/views/**/*.jst
18
+
19
+ stylesheets:
20
+ screen:
21
+ - public/stylesheets/screen.css
22
+ print:
23
+ - public/stylesheets/print.css
24
+ ie:
25
+ - public/stylesheets/ie.css
@@ -0,0 +1,8 @@
1
+ var App = {
2
+ Views: {},
3
+ Controllers: {},
4
+ Collections: {},
5
+ init: function() {
6
+ }
7
+ };
8
+
@@ -0,0 +1,12 @@
1
+ //////// Function to test for Mobile Safari. Returns true or false ///////////////////////////////////////////////////////////
2
+ function isiPhone() {
3
+ return (
4
+ (navigator.platform.indexOf("iPhone") !== -1) ||
5
+ (navigator.platform.indexOf("iPod") !== -1)
6
+ );
7
+ }
8
+
9
+ //////// DOCUMENT READY FOR JQUERY ///////////////////////////////////////////////////////////////////////////////////////////
10
+ $(function () {
11
+
12
+ });
@@ -0,0 +1,6 @@
1
+ document.createElement('header');
2
+ document.createElement('nav');
3
+ document.createElement('article');
4
+ document.createElement('section');
5
+ document.createElement('aside');
6
+ document.createElement('footer');
@@ -0,0 +1,132 @@
1
+ jQuery(function ($) {
2
+ var csrf_token = $('meta[name=csrf-token]').attr('content'),
3
+ csrf_param = $('meta[name=csrf-param]').attr('content');
4
+
5
+ $.fn.extend({
6
+ /**
7
+ * Triggers a custom event on an element and returns the event result
8
+ * this is used to get around not being able to ensure callbacks are placed
9
+ * at the end of the chain.
10
+ *
11
+ * TODO: deprecate with jQuery 1.4.2 release, in favor of subscribing to our
12
+ * own events and placing ourselves at the end of the chain.
13
+ */
14
+ triggerAndReturn: function (name, data) {
15
+ var event = new $.Event(name);
16
+ this.trigger(event, data);
17
+
18
+ return event.result !== false;
19
+ },
20
+
21
+ /**
22
+ * Handles execution of remote calls firing overridable events along the way
23
+ */
24
+ callRemote: function () {
25
+ var el = this,
26
+ method = el.attr('method') || el.attr('data-method') || 'GET',
27
+ url = el.attr('action') || el.attr('href'),
28
+ dataType = el.attr('data-type') || 'script';
29
+
30
+ if (url === undefined) {
31
+ throw "No URL specified for remote call (action or href must be present).";
32
+ } else {
33
+ if (el.triggerAndReturn('ajax:before')) {
34
+ var data = el.is('form') ? el.serializeArray() : [];
35
+ $.ajax({
36
+ url: url,
37
+ data: data,
38
+ dataType: dataType,
39
+ type: method.toUpperCase(),
40
+ beforeSend: function (xhr) {
41
+ el.trigger('ajax:loading', xhr);
42
+ },
43
+ success: function (data, status, xhr) {
44
+ el.trigger('ajax:success', [data, status, xhr]);
45
+ },
46
+ complete: function (xhr) {
47
+ el.trigger('ajax:complete', xhr);
48
+ },
49
+ error: function (xhr, status, error) {
50
+ el.trigger('ajax:failure', [xhr, status, error]);
51
+ }
52
+ });
53
+ }
54
+
55
+ el.trigger('ajax:after');
56
+ }
57
+ }
58
+ });
59
+
60
+ /**
61
+ * confirmation handler
62
+ */
63
+ $('a[data-confirm],input[data-confirm]').live('click', function () {
64
+ var el = $(this);
65
+ if (el.triggerAndReturn('confirm')) {
66
+ if (!confirm(el.attr('data-confirm'))) {
67
+ return false;
68
+ }
69
+ }
70
+ });
71
+
72
+
73
+ /**
74
+ * remote handlers
75
+ */
76
+ $('form[data-remote]').live('submit', function (e) {
77
+ $(this).callRemote();
78
+ e.preventDefault();
79
+ });
80
+
81
+ $('a[data-remote],input[data-remote]').live('click', function (e) {
82
+ $(this).callRemote();
83
+ e.preventDefault();
84
+ });
85
+
86
+ $('a[data-method]:not([data-remote])').live('click', function (e){
87
+ var link = $(this),
88
+ href = link.attr('href'),
89
+ method = link.attr('data-method'),
90
+ form = $('<form method="post" action="'+href+'"></form>'),
91
+ metadata_input = '<input name="_method" value="'+method+'" type="hidden" />';
92
+
93
+ if (csrf_param != null && csrf_token != null) {
94
+ metadata_input += '<input name="'+csrf_param+'" value="'+csrf_token+'" type="hidden" />';
95
+ }
96
+
97
+ form.hide()
98
+ .append(metadata_input)
99
+ .appendTo('body');
100
+
101
+ e.preventDefault();
102
+ form.submit();
103
+ });
104
+
105
+ /**
106
+ * disable-with handlers
107
+ */
108
+ var disable_with_input_selector = 'input[data-disable-with]';
109
+ var disable_with_form_remote_selector = 'form[data-remote]:has(' + disable_with_input_selector + ')';
110
+ var disable_with_form_not_remote_selector = 'form:not([data-remote]):has(' + disable_with_input_selector + ')';
111
+
112
+ var disable_with_input_function = function () {
113
+ $(this).find(disable_with_input_selector).each(function () {
114
+ var input = $(this);
115
+ input.data('enable-with', input.val())
116
+ .attr('value', input.attr('data-disable-with'))
117
+ .attr('disabled', 'disabled');
118
+ });
119
+ };
120
+
121
+ $(disable_with_form_remote_selector).live('ajax:before', disable_with_input_function);
122
+ $(disable_with_form_not_remote_selector).live('submit', disable_with_input_function);
123
+
124
+ $(disable_with_form_remote_selector).live('ajax:complete', function () {
125
+ $(this).find(disable_with_input_selector).each(function () {
126
+ var input = $(this);
127
+ input.removeAttr('disabled')
128
+ .val(input.data('enable-with'));
129
+ });
130
+ });
131
+
132
+ });
@@ -0,0 +1,6 @@
1
+ /*
2
+ IE7/IE8/IE9.js - copyright 2004-2010, Dean Edwards
3
+ http://code.google.com/p/ie7-js/
4
+ http://www.opensource.org/licenses/mit-license.php
5
+ */
6
+ ;(function(N,p){var h=N.IE7={version:"2.1(beta4)",toString:bT("[IE7]")};h.compat=9;var t=h.appVersion=navigator.appVersion.match(/MSIE (\d\.\d)/)[1]-0;if(/ie7_off/.test(top.location.search)||t<5.5||t>=h.compat)return;var E=t<6,bj=bT(),bx=p.documentElement,B,x,cy="!",U=":link{ie7-link:link}:visited{ie7-link:visited}",cz=/^[\w\.]+[^:]*$/;function bk(c,a){if(cz.test(c))c=(a||"")+c;return c};function by(c,a){c=bk(c,a);return c.slice(0,c.lastIndexOf("/")+1)};var bU=p.scripts[p.scripts.length-1],cA=by(bU.src);try{var V=new ActiveXObject("Microsoft.XMLHTTP")}catch(ex){}var bl={};function cB(c,a){try{c=bk(c,a);if(!bl[c]){V.open("GET",c,false);V.send();if(V.status==0||V.status==200){bl[c]=V.responseText}}}catch(ex){}return bl[c]||""};var dA=Array.prototype.slice,dB=/%([1-9])/g,cC=/^\s\s*/,cD=/\s\s*$/,cE=/([\/()[\]{}|*+-.,^$?\\])/g,bV=/\bbase\b/,bW=["constructor","toString"],bm;function F(){};F.extend=function(g,f){bm=true;var d=new this;O(d,g);bm=false;var c=d.constructor;function a(){if(!bm)c.apply(this,arguments)};d.constructor=a;a.extend=arguments.callee;O(a,f);a.prototype=d;return a};F.prototype.extend=function(a){return O(this,a)};var P="#",Q="#",bc=".",bn="/",dC=/\\(\d+)/g,cF=/\[(\\.|[^\]\\])+\]|\\.|\(\?/g,cG=/\(/g,cH=/\$(\d+)/,cI=/^\$\d+$/,cJ=/(\[(\\.|[^\]\\])+\]|\\.|\(\?)|\(/g,cK=/^<#\w+>$/,cL=/<#(\w+)>/g,G=F.extend({constructor:function(a){this[bc]=[];this[Q]={};this.merge(a)},add:function(c,a){delete this[bn];if(c instanceof RegExp){c=c.source}if(!this[P+c])this[bc].push(String(c));return this[Q][P+c]=new G.Item(c,a,this)},compile:function(a){if(a||!this[bn]){this[bn]=new RegExp(this,this.ignoreCase?"gi":"g")}return this[bn]},merge:function(c){for(var a in c)this.add(a,c[a])},exec:function(o){var k=this,l=k[bc],m=k[Q],j,i=this.compile(true).exec(o);if(i){var g=0,f=1;while((j=m[P+l[g++]])){var d=f+j.length+1;if(i[f]){if(j.replacement===0){return k.exec(o)}else{var c=i.slice(f,d),a=c.length;while(--a)c[a]=c[a]||"";c[0]={match:c[0],item:j};return c}}f=d}}return null},parse:function(o){o+="";var k=this,l=k[bc],m=k[Q];return o.replace(this.compile(),function(j){var i=[],g,f=1,d=arguments.length;while(--d)i[d]=arguments[d]||"";while((g=m[P+l[d++]])){var c=f+g.length+1;if(i[f]){var a=g.replacement;switch(typeof a){case"function":return a.apply(k,i.slice(f,c));case"number":return i[f+a];default:return a}}f=c}return j})},toString:function(){var g=[],f=this[bc],d=this[Q],c;for(var a=0;c=d[P+f[a]];a++){g[a]=c.source}return"("+g.join(")|(")+")"}},{IGNORE:null,Item:F.extend({constructor:function(k,l,m){var j=k.indexOf("(")===-1?0:G.count(k),i=m.dictionary;if(i&&k.indexOf("<#")!==-1){if(cK.test(k)){var g=i[Q][P+k.slice(2,-1)];k=g.replacement;j=g._5}else{k=i.parse(k)}}if(typeof l=="number")l=String(l);else if(l==null)l=0;if(typeof l=="string"&&cH.test(l)){if(cI.test(l)){var f=l.slice(1)-0;if(f&&f<=j)l=f}else{var d=l,c;l=function(a){if(!c){c=new RegExp(k,"g"+(this.ignoreCase?"i":""))}return a.replace(c,d)}}}this.length=j;this.source=String(k);this.replacement=l}}),count:function(a){return(String(a).replace(cF,"").match(cG)||"").length}}),cM=G.extend({parse:function(f){var d=this[Q];return f.replace(cL,function(c,a){a=d[P+a];return a?a._6:c})},add:function(g,f){if(f instanceof RegExp){f=f.source}var d=f.replace(cJ,cN);if(f.indexOf("(")!==-1){var c=G.count(f)}if(f.indexOf("<#")!==-1){f=this.parse(f);d=this.parse(d)}var a=this.base(g,f);a._6=d;a._5=c||a.length;return a},toString:function(){return"(<#"+this[PATTERNS].join(">)|(<#")+">)"}});function cN(c,a){return a||"(?:"};function O(i,g){if(i&&g){var f=(typeof g=="function"?Function:Object).prototype;var d=bW.length,c;if(bm)while(c=bW[--d]){var a=g[c];if(a!=f[c]){if(bV.test(a)){bX(i,c,a)}else{i[c]=a}}}for(c in g)if(typeof f[c]=="undefined"){var a=g[c];if(i[c]&&typeof a=="function"&&bV.test(a)){bX(i,c,a)}else{i[c]=a}}}return i};function bX(i,g,f){var d=i[g];i[g]=function(){var c=this.base;this.base=d;var a=f.apply(this,arguments);this.base=c;return a}};function cO(f,d){if(!d)d=f;var c={};for(var a in f)c[a]=d[a];return c};function H(g){var f=arguments,d=new RegExp("%([1-"+arguments.length+"])","g");return String(g).replace(d,function(c,a){return a<f.length?f[a]:c})};function bo(c,a){return String(c).match(a)||[]};function bY(a){return String(a).replace(cE,"\\$1")};function bZ(a){return String(a).replace(cC,"").replace(cD,"")};function bT(a){return function(){return a}};var ca=G.extend({ignoreCase:true}),cP=/'/g,cb=/'(\d+)'/g,dD=/\\/g,bz=/\\([nrtf'"])/g,W=[],cc=new ca({"<!\\-\\-|\\-\\->":"","\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\/":"","@(namespace|import)[^;\\n]+[;\\n]":"","'(\\\\.|[^'\\\\])*'":cd,'"(\\\\.|[^"\\\\])*"':cd,"\\s+":" "});function cQ(a){return cc.parse(a).replace(bz,"$1")};function bd(a){return a.replace(cb,cR)};function cd(c){var a=W.length;W[a]=c.slice(1,-1).replace(bz,"$1").replace(cP,"\\'");return"'"+a+"'"};function cR(d,c){var a=W[c];if(a==null)return d;return"'"+W[c]+"'"};function bp(a){return a.indexOf("'")===0?W[a.slice(1,-1)]:a};var cS=new G({Width:"Height",width:"height",Left:"Top",left:"top",Right:"Bottom",right:"bottom",onX:"onY"});function ce(a){return cS.parse(a)};var cf=[];function bA(a){cT(a);y(N,"onresize",a)};function y(d,c,a){d.attachEvent(c,a);cf.push(arguments)};function cU(d,c,a){try{d.detachEvent(c,a)}catch(ex){}};y(N,"onunload",function(){var a;while(a=cf.pop()){cU(a[0],a[1],a[2])}});function be(d,c,a){if(!d.elements)d.elements={};if(a)d.elements[c.uniqueID]=c;else delete d.elements[c.uniqueID];return a};y(N,"onbeforeprint",function(){if(!h.CSS.print)new cg("print");h.CSS.print.recalc()});var ch=/^\d+(px)?$/i,X=/^\d+%$/,C=function(f,d){if(ch.test(d))return parseInt(d);var c=f.style.left,a=f.runtimeStyle.left;f.runtimeStyle.left=f.currentStyle.left;f.style.left=d||0;d=f.style.pixelLeft;f.style.left=c;f.runtimeStyle.left=a;return d},bB="ie7-",ci=F.extend({constructor:function(){this.fixes=[];this.recalcs=[]},init:bj}),bC=[];function cT(a){bC.push(a)};h.recalc=function(){h.HTML.recalc();h.CSS.recalc();for(var a=0;a<bC.length;a++)bC[a]()};function bq(a){return a.currentStyle["ie7-position"]=="fixed"};function bD(c,a){return c.currentStyle[bB+a]||c.currentStyle[a]};function Y(d,c,a){if(d.currentStyle[bB+c]==null){d.runtimeStyle[bB+c]=d.currentStyle[c]}d.runtimeStyle[c]=a};function cj(c){var a=p.createElement(c||"object");a.style.cssText="position:absolute;padding:0;display:block;border:none;clip:rect(0 0 0 0);left:-9999";a.ie7_anon=true;return a};var bE="(e.nextSibling&&IE7._1(e,'next'))",ck=bE.replace(/next/g,"previous"),cl="e.nodeName>'@'",cm="if("+cl+"){",cn="(e.nodeName==='FORM'?IE7._0(e,'id'):e.id)",cV=/a(#[\w-]+)?(\.[\w-]+)?:(hover|active)/i,cW=/(.*)(:first-(line|letter))/,cX=/\s/,cY=/((?:\\.|[^{\\])+)\{((?:\\.|[^}\\])+)\}/g,cZ=/(?:\\.|[^,\\])+/g,I=p.styleSheets,bF=[];h.CSS=new(ci.extend({parser:new ca,screen:"",print:"",styles:[],rules:[],pseudoClasses:t<7?"first\\-child":"",dynamicPseudoClasses:{toString:function(){var c=[];for(var a in this)c.push(a);return c.join("|")}},init:function(){var j="^\x01$",i="\\[class=?[^\\]]*\\]",g=[];if(this.pseudoClasses)g.push(this.pseudoClasses);var f=this.dynamicPseudoClasses.toString();if(f)g.push(f);g=g.join("|");var d=t<7?["[>+~\\[(]|([:.])[\\w-]+\\1"]:[i];if(g)d.push(":("+g+")");this.UNKNOWN=new RegExp(d.join("|")||j,"i");var c=t<7?["\\[[^\\]]+\\]|[^\\s(\\[]+\\s*[+~]"]:[i],a=c.concat();if(g)a.push(":("+g+")");u.COMPLEX=new RegExp(a.join("|")||j,"ig");if(this.pseudoClasses)c.push(":("+this.pseudoClasses+")");bf.COMPLEX=new RegExp(c.join("|")||j,"i");f="not\\(:"+f.split("|").join("\\)|not\\(:")+"\\)|"+f;bf.MATCH=new RegExp(f?"(.*?):("+f+")(.*)":j,"i");this.createStyleSheet();this.refresh()},addEventHandler:function(){y.apply(null,arguments)},addFix:function(c,a){this.parser.add(c,a)},addRecalc:function(i,g,f,d){i=i.source||i;g=new RegExp("([{;\\s])"+i+"\\s*:\\s*"+g+"[^;}]*");var c=this.recalcs.length;if(typeof d=="string")d=i+":"+d;this.addFix(g,function(a){if(typeof d=="function")d=d(a);return(d?d:a)+";ie7-"+a.slice(1)+";ie7_recalc"+c+":1"});this.recalcs.push(arguments);return c},apply:function(){this.getInlineCSS();new cg("screen");this.trash()},createStyleSheet:function(){p.getElementsByTagName("head")[0].appendChild(p.createElement("style"));this.styleSheet=I[I.length-1];this.styleSheet.ie7=true;this.styleSheet.owningElement.ie7=true;this.styleSheet.cssText=U},getInlineCSS:function(){var d=p.getElementsByTagName("style"),c;for(var a=d.length-1;c=d[a];a--){if(!c.disabled&&!c.ie7){c._7=c.innerHTML}}},getText:function(d,c){try{var a=d.cssText}catch(e){a=""}if(V)a=cB(d.href,c)||a;return a},recalc:function(){this.screen.recalc();var q=/ie7_recalc\d+/g,n=U.match(/[{,]/g).length,o=this.styleSheet.rules,k,l,m,j,i,g,f,d,c;for(g=n;k=o[g];g++){var a=k.style.cssText;if(l=a.match(q)){j=J(k.selectorText);if(j.length)for(f=0;f<l.length;f++){c=l[f];m=h.CSS.recalcs[c.slice(10)][2];for(d=0;(i=j[d]);d++){if(i.currentStyle[c])m(i,a)}}}}},refresh:function(){this.styleSheet.cssText=U+this.screen+this.print},trash:function(){for(var c=0;c<I.length;c++){if(!I[c].ie7){try{var a=I[c].cssText}catch(e){a=""}if(a)I[c].cssText=""}}}}));var cg=F.extend({constructor:function(a){this.media=a;this.load();h.CSS[a]=this;h.CSS.refresh()},createRule:function(d,c){var a;if(R&&(a=d.match(R.MATCH))){return new R(a[1],a[2],c)}else if(a=d.match(bf.MATCH)){if(!cV.test(a[0])||bf.COMPLEX.test(a[0])){return new bf(d,a[1],a[2],a[3],c)}}else{return new u(d,c)}return d+" {"+c+"}"},getText:function(){var v=/@media\s+([^{]+?)\s*\{([^@]+\})\s*\}/gi,Z=/@import[^;\n]+/gi,S=/@import\s+url\s*\(\s*["']?|["']?\s*\)\s*/gi,ba=/(url\s*\(\s*['"]?)([\w\.]+[^:\)]*['"]?\))/gi,K=this,L={};function z(k,l,m,j){var i="";if(!j){m=q(k.media);j=0}if(m==="none"){k.disabled=true;return""}if(m==="all"||m===K.media){try{var g=!!k.cssText}catch(exe){}if(j<3&&g){var f=k.cssText.match(Z);for(var d=0,c;d<k.imports.length;d++){var c=k.imports[d];var a=k._2||k.href;c._2=f[d].replace(S,"");i+=z(c,by(a,l),m,j+1)}}i+=cQ(k.href?n(k,l):k.owningElement._7);i=A(i,K.media)}return i};for(var w=0;w<I.length;w++){var r=I[w];if(!r.disabled&&!r.ie7)this.cssText+=z(r)}function A(c,a){s.value=a;return c.replace(v,s)};function s(d,c,a){c=q(c);switch(c){case"screen":case"print":if(c!==s.value)return"";case"all":return a}return""};function q(d){if(!d)return"all";var c=d.toLowerCase().split(/\s*,\s*/);d="none";for(var a=0;a<c.length;a++){if(c[a]==="all")return"all";if(c[a]==="screen"){if(d==="print")return"all";d="screen"}else if(c[a]==="print"){if(d==="screen")return"all";d="print"}}return d};function n(f,d){var c=f._2||f.href,a=bk(c,d);if(L[a])return"";L[a]=f.disabled?"":o(h.CSS.getText(f,d),by(c,d));return L[a]};function o(c,a){return c.replace(ba,"$1"+a.slice(0,a.lastIndexOf("/")+1)+"$2")}},load:function(){this.cssText="";this.getText();this.parse();if(bF.length){this.cssText=da(this.cssText)}this.cssText=bd(this.cssText);bl={}},parse:function(){var j=h.CSS.parser.parse(this.cssText),o="";this.cssText=j.replace(/@charset[^;]+;|@font\-face[^\}]+\}/g,function(a){o+=a+"\n";return""});this.declarations=bd(o);var k=h.CSS.rules.length,l=[],m;while((m=cY.exec(this.cssText))){var j=m[2];if(j){var i=t<7&&j.indexOf("AlphaImageLoader")!==-1;var g=m[1].match(cZ),f;for(var d=0;f=g[d];d++){f=bZ(f);var c=h.CSS.UNKNOWN.test(f);g[d]=c?this.createRule(f,j):f+"{"+j+"}";if(i)g[d]+=this.createRule(f+">*","position:relative")}l.push(g.join("\n"))}}this.cssText=l.join("\n");this.rules=h.CSS.rules.slice(k)},recalc:function(){var c,a;for(a=0;(c=this.rules[a]);a++)c.recalc()},toString:function(){return this.declarations+"@media "+this.media+"{"+this.cssText+"}"}}),R,u=h.Rule=F.extend({constructor:function(d,c){this.id=h.CSS.rules.length;this.className=u.PREFIX+this.id;var a=d.match(cW);this.selector=(a?a[1]:d)||"*";this.selectorText=this.parse(this.selector)+(a?a[2]:"");this.cssText=c;this.MATCH=new RegExp("\\s"+this.className+"(\\s|$)","g");h.CSS.rules.push(this);this.init()},init:bj,add:function(a){a.className+=" "+this.className},recalc:function(){var c=J(this.selector);for(var a=0;a<c.length;a++)this.add(c[a])},parse:function(g){var f=g.replace(u.CHILD," ").replace(u.COMPLEX,"");if(t<7)f=f.replace(u.MULTI,"");var d=bo(f,u.TAGS).length-bo(g,u.TAGS).length,c=bo(f,u.CLASSES).length-bo(g,u.CLASSES).length+1;while(c>0&&u.CLASS.test(f)){f=f.replace(u.CLASS,"");c--}while(d>0&&u.TAG.test(f)){f=f.replace(u.TAG,"$1*");d--}f+="."+this.className;c=Math.min(c,2);d=Math.min(d,2);var a=-10*c-d;if(a>0){f=f+","+u.MAP[a]+" "+f}return f},remove:function(a){a.className=a.className.replace(this.MATCH,"$1")},toString:function(){return H("%1 {%2}",this.selectorText,this.cssText)}},{CHILD:/>/g,CLASS:/\.[\w-]+/,CLASSES:/[.:\[]/g,MULTI:/(\.[\w-]+)+/g,PREFIX:"ie7_class",TAG:/^\w+|([\s>+~])\w+/,TAGS:/^\w|[\s>+~]\w/g,MAP:{"1":"html","2":"html body","10":".ie7_html","11":"html.ie7_html","12":"html.ie7_html body","20":".ie7_html .ie7_body","21":"html.ie7_html .ie7_body","22":"html.ie7_html body.ie7_body"}}),bf=u.extend({constructor:function(g,f,d,c,a){this.negated=d.indexOf("not")===0;if(this.negated)d=d.slice(5,-1);this.attach=f||"*";this.dynamicPseudoClass=h.CSS.dynamicPseudoClasses[d];this.target=c;this.base(g,a)},recalc:function(){var f=J(this.attach),d;for(var c=0;d=f[c];c++){var a=this.target?J(this.target,d):[d];if(a.length)this.dynamicPseudoClass.apply(d,a,this)}}}),M=F.extend({constructor:function(c,a){this.name=c;this.apply=a;this.instances={};h.CSS.dynamicPseudoClasses[c]=this},register:function(g,f){var d=g[2];if(!f&&d.negated){this.unregister(g,true)}else{g.id=d.id+g[0].uniqueID;if(!this.instances[g.id]){var c=g[1],a;for(a=0;a<c.length;a++)d.add(c[a]);this.instances[g.id]=g}}},unregister:function(g,f){var d=g[2];if(!f&&d.negated){this.register(g,true)}else{if(this.instances[g.id]){var c=g[1],a;for(a=0;a<c.length;a++)d.remove(c[a]);delete this.instances[g.id]}}}}),br=new M("hover",function(c){var a=arguments;h.CSS.addEventHandler(c,"onmouseenter",function(){br.register(a)});h.CSS.addEventHandler(c,"onmouseleave",function(){br.unregister(a)})});y(p,"onmouseup",function(){var c=br.instances;for(var a in c)if(!c[a][0].contains(event.srcElement))br.unregister(c[a])});var co={"=":"%1==='%2'","~=":"(' '+%1+' ').indexOf(' %2 ')!==-1","|=":"%1==='%2'||%1.indexOf('%2-')===0","^=":"%1.indexOf('%2')===0","$=":"%1.slice(-'%2'.length)==='%2'","*=":"%1.indexOf('%2')!==-1"};co[""]="%1!=null";var T={"<#attr>":function(g,f,d,c){var a="IE7._0(e,'"+f+"')";c=bp(c);if(d.length>1){if(!c||d==="~="&&cX.test(c)){return"false&&"}a="("+a+"||'')"}return"("+H(co[d],a,c)+")&&"},"<#id>":cn+"==='$1'&&","<#class>":"e.className&&(' '+e.className+' ').indexOf(' $1 ')!==-1&&",":first-child":"!"+ck+"&&",":link":"e.currentStyle['ie7-link']=='link'&&",":visited":"e.currentStyle['ie7-link']=='visited'&&"};h.HTML=new(ci.extend({fixed:{},init:bj,addFix:function(){this.fixes.push(arguments)},apply:function(){for(var f=0;f<this.fixes.length;f++){var d=J(this.fixes[f][0]);var c=this.fixes[f][1];for(var a=0;a<d.length;a++)c(d[a])}},addRecalc:function(){this.recalcs.push(arguments)},recalc:function(){for(var j=0;j<this.recalcs.length;j++){var i=J(this.recalcs[j][0]);var g=this.recalcs[j][1],f;var d=Math.pow(2,j);for(var c=0;(f=i[c]);c++){var a=f.uniqueID;if((this.fixed[a]&d)===0){f=g(f)||f;this.fixed[a]|=d}}}}}));if(t<7){p.createElement("abbr");h.HTML.addRecalc("label",function(c){if(!c.htmlFor){var a=J("input,textarea",c,true);if(a){y(c,"onclick",function(){a.click()})}}})}var bg="[.\\d]";(function(){var v=h.Layout={};U+="*{boxSizing:content-box}";v.boxSizing=function(a){if(!a.currentStyle.hasLayout){a.style.height="0cm";if(a.currentStyle.verticalAlign==="auto")a.runtimeStyle.verticalAlign="top";Z(a)}};function Z(a){if(a!=x&&a.currentStyle.position!=="absolute"){S(a,"marginTop");S(a,"marginBottom")}};function S(g,f){if(!g.runtimeStyle[f]){var d=g.parentElement;var c=f==="marginTop";if(d&&d.currentStyle.hasLayout&&!h._1(g,c?"previous":"next"))return;var a=g[c?"firstChild":"lastChild"];if(a&&a.nodeName<"@")a=h._1(a,c?"next":"previous");if(a&&a.currentStyle.styleFloat==="none"&&a.currentStyle.hasLayout){S(a,f);margin=ba(g,g.currentStyle[f]);childMargin=ba(a,a.currentStyle[f]);if(margin<0||childMargin<0){g.runtimeStyle[f]=margin+childMargin}else{g.runtimeStyle[f]=Math.max(childMargin,margin)}a.runtimeStyle[f]="0px"}}};function ba(c,a){return a==="auto"?0:C(c,a)};var K=/^[.\d][\w]*$/,L=/^(auto|0cm)$/,z={};v.borderBox=function(a){z.Width(a);z.Height(a)};var w=function(r){z.Width=function(a){if(!X.test(a.currentStyle.width))A(a);if(r)Z(a)};function A(c,a){if(!c.runtimeStyle.fixedWidth){if(!a)a=c.currentStyle.width;c.runtimeStyle.fixedWidth=K.test(a)?Math.max(0,n(c,a))+"px":a;Y(c,"width",c.runtimeStyle.fixedWidth)}};function s(c){if(!bq(c)){var a=c.offsetParent;while(a&&!a.currentStyle.hasLayout)a=a.offsetParent}return(a||x).clientWidth};function q(c,a){if(X.test(a))return parseInt(parseFloat(a)/100*s(c));return C(c,a)};var n=function(f,d){var c=f.currentStyle["ie7-box-sizing"]==="border-box",a=0;if(E&&!c)a+=o(f)+k(f,"padding");else if(!E&&c)a-=o(f)+k(f,"padding");return q(f,d)+a};function o(a){return a.offsetWidth-a.clientWidth};function k(c,a){return q(c,c.currentStyle[a+"Left"])+q(c,c.currentStyle[a+"Right"])};U+="*{minWidth:none;maxWidth:none;min-width:none;max-width:none}";v.minWidth=function(a){if(a.currentStyle["min-width"]!=null){a.style.minWidth=a.currentStyle["min-width"]}if(be(arguments.callee,a,a.currentStyle.minWidth!=="none")){v.boxSizing(a);A(a);l(a)}};eval("IE7.Layout.maxWidth="+String(v.minWidth).replace(/min/g,"max"));function l(d){if(d==p.body){var c=d.clientWidth}else{var a=d.getBoundingClientRect();c=a.right-a.left}if(d.currentStyle.minWidth!=="none"&&c<n(d,d.currentStyle.minWidth)){d.runtimeStyle.width=d.currentStyle.minWidth}else if(d.currentStyle.maxWidth!=="none"&&c>=n(d,d.currentStyle.maxWidth)){d.runtimeStyle.width=d.currentStyle.maxWidth}else{d.runtimeStyle.width=d.runtimeStyle.fixedWidth}};function m(a){if(be(m,a,/^(fixed|absolute)$/.test(a.currentStyle.position)&&bD(a,"left")!=="auto"&&bD(a,"right")!=="auto"&&L.test(bD(a,"width")))){j(a);v.boxSizing(a)}};v.fixRight=m;function j(d){var c=q(d,d.runtimeStyle._3||d.currentStyle.left),a=s(d)-q(d,d.currentStyle.right)-c-k(d,"margin");if(parseInt(d.runtimeStyle.width)===a)return;d.runtimeStyle.width="";if(bq(d)||r||d.offsetWidth<a){if(!E)a-=o(d)+k(d,"padding");if(a<0)a=0;d.runtimeStyle.fixedWidth=a;Y(d,"width",a)}};var i=0;bA(function(){if(!x)return;var g,f=(i<x.clientWidth);i=x.clientWidth;var d=v.minWidth.elements;for(g in d){var c=d[g];var a=(parseInt(c.runtimeStyle.width)===n(c,c.currentStyle.minWidth));if(f&&a)c.runtimeStyle.width="";if(f==a)l(c)}var d=v.maxWidth.elements;for(g in d){var c=d[g];var a=(parseInt(c.runtimeStyle.width)===n(c,c.currentStyle.maxWidth));if(!f&&a)c.runtimeStyle.width="";if(f!==a)l(c)}for(g in m.elements)j(m.elements[g])});if(E){h.CSS.addRecalc("width",bg,z.Width)}if(t<7){h.CSS.addRecalc("max-width",bg,v.maxWidth);h.CSS.addRecalc("right",bg,m)}else if(t==7){if(r)h.CSS.addRecalc("height","[\\d.]+%",function(element){element.runtimeStyle.pixelHeight=parseInt(s(element)*element.currentStyle["ie7-height"].slice(0,-1)/100)})}};eval("var _8="+ce(w));w();_8(true);if(t<7){h.CSS.addRecalc("min-width",bg,v.minWidth);h.CSS.addFix(/\bmin-height\s*/,"height")}})();var bG=bk("blank.gif",cA),bH="DXImageTransform.Microsoft.AlphaImageLoader",cp="progid:"+bH+"(src='%1',sizingMethod='%2')",bh,bi=[];function cq(c){if(bh.test(c.src)){var a=new Image(c.width,c.height);a.onload=function(){c.width=a.width;c.height=a.height;a=null};a.src=c.src;c.pngSrc=c.src;bs(c)}};if(t<7){h.CSS.addFix(/background(-image)?\s*:\s*([^};]*)?url\(([^\)]+)\)([^;}]*)?/,function(g,f,d,c,a){c=bp(c);return bh.test(c)?"filter:"+H(cp,c,a.indexOf("no-repeat")===-1?"scale":"crop")+";zoom:1;background"+(f||"")+":"+(d||"")+"none"+(a||""):g});h.CSS.addRecalc(/list\-style(\-image)?/,"[^};]*url",function(f){var d=f.currentStyle.listStyleImage.slice(5,-2);if(bh.test(d)){if(f.nodeName==="LI"){cr(f,d)}else if(f.nodeName==="UL"){for(var c=0,a;a=f.childNodes[c];c++){if(a.nodeName==="LI")cr(a,d)}}}});function cr(i,g){var f=i.runtimeStyle,d=i.offsetHeight,c=new Image;c.onload=function(){var a=i.currentStyle.paddingLeft;a=a==="0px"?0:C(i,a);f.paddingLeft=(a+this.width)+"px";f.marginLeft=-this.width+"px";f.listStyleType="none";f.listStyleImage="none";f.paddingTop=Math.max(d-i.offsetHeight,0)+"px";bs(i,"crop",g);i.style.zoom="100%"};c.src=g};h.HTML.addRecalc("img,input",function(a){if(a.nodeName==="INPUT"&&a.type!=="image")return;cq(a);y(a,"onpropertychange",function(){if(!bI&&event.propertyName==="src"&&a.src.indexOf(bG)===-1)cq(a)})});var bI=false;y(N,"onbeforeprint",function(){bI=true;for(var a=0;a<bi.length;a++)db(bi[a])});y(N,"onafterprint",function(){for(var a=0;a<bi.length;a++)bs(bi[a]);bI=false})}function bs(f,d,c){var a=f.filters[bH];if(a){a.src=c||f.src;a.enabled=true}else{f.runtimeStyle.filter=H(cp,c||f.src,d||"scale");bi.push(f)}f.src=bG};function db(a){a.src=a.pngSrc;a.filters[bH].enabled=false};(function(){if(t>=7)return;h.CSS.addRecalc("position","fixed",o,"absolute");h.CSS.addRecalc("background(-attachment)?","[^};]*fixed",q);var z=E?"body":"documentElement";function w(){if(B.currentStyle.backgroundAttachment!=="fixed"){if(B.currentStyle.backgroundImage==="none"){B.runtimeStyle.backgroundRepeat="no-repeat";B.runtimeStyle.backgroundImage="url("+bG+")"}B.runtimeStyle.backgroundAttachment="fixed"}w=bj};var r=cj("img");function A(a){return a?bq(a)||A(a.parentElement):false};function s(d,c,a){setTimeout("document.all."+d.uniqueID+".runtimeStyle.setExpression('"+c+"','"+a+"')",0)};function q(a){if(be(q,a,a.currentStyle.backgroundAttachment==="fixed"&&!a.contains(B))){w();j.bgLeft(a);j.bgTop(a);n(a)}};function n(c){r.src=c.currentStyle.backgroundImage.slice(5,-2);var a=c.canHaveChildren?c:c.parentElement;a.appendChild(r);j.setOffsetLeft(c);j.setOffsetTop(c);a.removeChild(r)};function o(a){if(be(o,a,bq(a))){Y(a,"position","absolute");Y(a,"left",a.currentStyle.left);Y(a,"top",a.currentStyle.top);w();h.Layout.fixRight(a);k(a)}};function k(d,c){p.body.getBoundingClientRect();j.positionTop(d,c);j.positionLeft(d,c,true);if(!d.runtimeStyle.autoLeft&&d.currentStyle.marginLeft==="auto"&&d.currentStyle.right!=="auto"){var a=x.clientWidth-j.getPixelWidth(d,d.currentStyle.right)-j.getPixelWidth(d,d.runtimeStyle._3)-d.clientWidth;if(d.currentStyle.marginRight==="auto")a=parseInt(a/2);if(A(d.offsetParent))d.runtimeStyle.pixelLeft+=a;else d.runtimeStyle.shiftLeft=a}if(!d.runtimeStyle.fixedWidth)j.clipWidth(d);if(!d.runtimeStyle.fixedHeight)j.clipHeight(d)};function l(){var c=q.elements;for(var a in c)n(c[a]);c=o.elements;for(a in c){k(c[a],true);k(c[a],true)}m=0};var m;bA(function(){if(!m)m=setTimeout(l,100)});var j={},i=function(g){g.bgLeft=function(a){a.style.backgroundPositionX=a.currentStyle.backgroundPositionX;if(!A(a)){s(a,"backgroundPositionX","(parseInt(runtimeStyle.offsetLeft)+document."+z+".scrollLeft)||0")}};g.setOffsetLeft=function(c){var a=A(c)?"backgroundPositionX":"offsetLeft";c.runtimeStyle[a]=g.getOffsetLeft(c,c.style.backgroundPositionX)-c.getBoundingClientRect().left-c.clientLeft+2};g.getOffsetLeft=function(c,a){switch(a){case"left":case"top":return 0;case"right":case"bottom":return x.clientWidth-r.offsetWidth;case"center":return(x.clientWidth-r.offsetWidth)/2;default:if(X.test(a)){return parseInt((x.clientWidth-r.offsetWidth)*parseFloat(a)/100)}r.style.left=a;return r.offsetLeft}};g.clipWidth=function(f){var d=f.runtimeStyle.fixWidth;f.runtimeStyle.borderRightWidth="";f.runtimeStyle.width=d?g.getPixelWidth(f,d)+"px":"";if(f.currentStyle.width!=="auto"){var c=f.getBoundingClientRect();var a=f.offsetWidth-x.clientWidth+c.left-2;if(a>=0){f.runtimeStyle.borderRightWidth="0px";a=Math.max(C(f,f.currentStyle.width)-a,0);Y(f,"width",a);return a}}};g.positionLeft=function(c,a){if(!a&&X.test(c.currentStyle.width)){c.runtimeStyle.fixWidth=c.currentStyle.width}if(c.runtimeStyle.fixWidth){c.runtimeStyle.width=g.getPixelWidth(c,c.runtimeStyle.fixWidth)}c.runtimeStyle.shiftLeft=0;c.runtimeStyle._3=c.currentStyle.left;c.runtimeStyle.autoLeft=c.currentStyle.right!=="auto"&&c.currentStyle.left==="auto";c.runtimeStyle.left="";c.runtimeStyle.screenLeft=g.getScreenLeft(c);c.runtimeStyle.pixelLeft=c.runtimeStyle.screenLeft;if(!a&&!A(c.offsetParent)){s(c,"pixelLeft","runtimeStyle.screenLeft+runtimeStyle.shiftLeft+document."+z+".scrollLeft")}};g.getScreenLeft=function(d){var c=d.offsetLeft,a=1;if(d.runtimeStyle.autoLeft){c=x.clientWidth-d.offsetWidth-g.getPixelWidth(d,d.currentStyle.right)}if(d.currentStyle.marginLeft!=="auto"){c-=g.getPixelWidth(d,d.currentStyle.marginLeft)}while(d=d.offsetParent){if(d.currentStyle.position!=="static")a=-1;c+=d.offsetLeft*a}return c};g.getPixelWidth=function(c,a){return X.test(a)?parseInt(parseFloat(a)/100*x.clientWidth):C(c,a)}};eval("var _9="+ce(i));i(j);_9(j)})();if(t<7){var bJ={backgroundColor:"transparent",backgroundImage:"none",backgroundPositionX:null,backgroundPositionY:null,backgroundRepeat:null,borderTopWidth:0,borderRightWidth:0,borderBottomWidth:0,borderLeftStyle:"none",borderTopStyle:"none",borderRightStyle:"none",borderBottomStyle:"none",borderLeftWidth:0,borderLeftColor:"#000",borderTopColor:"#000",borderRightColor:"#000",borderBottomColor:"#000",height:null,marginTop:0,marginBottom:0,marginRight:0,marginLeft:0,width:"100%"};h.CSS.addRecalc("overflow","visible",function(d){if(d.currentStyle.position==="absolute")return;if(d.parentNode.ie7_wrapped)return;if(h.Layout&&d.currentStyle["max-height"]!=="auto"){h.Layout.maxHeight(d)}if(d.currentStyle.marginLeft==="auto")d.style.marginLeft=0;if(d.currentStyle.marginRight==="auto")d.style.marginRight=0;var c=p.createElement(cy);c.ie7_wrapped=d;for(var a in bJ){c.style[a]=d.currentStyle[a];if(bJ[a]!=null){d.runtimeStyle[a]=bJ[a]}}c.style.display="block";c.style.position="relative";d.runtimeStyle.position="absolute";d.parentNode.insertBefore(c,d);c.appendChild(d)})}function dc(){var s="xx-small,x-small,small,medium,large,x-large,xx-large".split(",");for(var q=0;q<s.length;q++){s[s[q]]=s[q-1]||"0.67em"}h.CSS.addFix(/(font(-size)?\s*:\s*)([\w.-]+)/,function(f,d,c,a){return d+(s[a]||a)});var n=/^\-/,o=/(em|ex)$/i,k=/em$/i,l=/ex$/i;C=function(d,c){if(ch.test(c))return parseInt(c)||0;var a=n.test(c)?-1:1;if(o.test(c))a*=j(d);m.style.width=a<0?c.slice(1):c;B.appendChild(m);c=a*m.offsetWidth;m.removeNode();return parseInt(c)};var m=cj();function j(d){var c=1;m.style.fontFamily=d.currentStyle.fontFamily;m.style.lineHeight=d.currentStyle.lineHeight;while(d!=B){var a=d.currentStyle["ie7-font-size"];if(a){if(k.test(a))c*=parseFloat(a);else if(X.test(a))c*=(parseFloat(a)/100);else if(l.test(a))c*=(parseFloat(a)/2);else{m.style.fontSize=a;return 1}}d=d.parentElement}return c};h.CSS.addFix(/cursor\s*:\s*pointer/,"cursor:hand");h.CSS.addFix(/display\s*:\s*list-item/,"display:block");function i(f){var d=f.parentElement,c=d.offsetWidth-f.offsetWidth-g(d),a=(f.currentStyle["ie7-margin"]&&f.currentStyle.marginRight==="auto")||f.currentStyle["ie7-margin-right"]==="auto";switch(d.currentStyle.textAlign){case"right":c=a?parseInt(c/2):0;f.runtimeStyle.marginRight=c+"px";break;case"center":if(a)c=0;default:if(a)c/=2;f.runtimeStyle.marginLeft=parseInt(c)+"px"}};function g(a){return C(a,a.currentStyle.paddingLeft)+C(a,a.currentStyle.paddingRight)};h.CSS.addRecalc("margin(-left|-right)?","[^};]*auto",function(a){if(be(i,a,a.parentElement&&a.currentStyle.display==="block"&&a.currentStyle.marginLeft==="auto"&&a.currentStyle.position!=="absolute")){i(a)}});bA(function(){for(var c in i.elements){var a=i.elements[c];a.runtimeStyle.marginLeft=a.runtimeStyle.marginRight="";i(a)}})};var bK="\\([^)]+\\)";cc.add(/::(before|after)/,":$1");if(t<8){if(h.CSS.pseudoClasses)h.CSS.pseudoClasses+="|";h.CSS.pseudoClasses+="before|after|lang"+bK;function da(a){return a.replace(new RegExp("([{;\\s])("+bF.join("|")+")\\s*:\\s*([^;}]+)","g"),"$1$2:$3;ie7-$2:$3")};var dd=/[\w-]+\s*:\s*inherit/g;var de=/ie7\-|\s*:\s*inherit/g;var df=/\-([a-z])/g;function dg(c,a){return a.toUpperCase()};h.CSS.addRecalc("[\\w-]+","inherit",function(g,f){if(g.parentElement){var d=f.match(dd);for(var c=0;c<d.length;c++){var a=d[c].replace(de,"");if(g.currentStyle["ie7-"+a]==="inherit"){a=a.replace(df,dg);g.runtimeStyle[a]=g.parentElement.currentStyle[a]}}}},function(a){bF.push(bY(a.slice(1).split(":")[0]));return a});var bt=new M("focus",function(c){var a=arguments;h.CSS.addEventHandler(c,"onfocus",function(){bt.unregister(a);bt.register(a)});h.CSS.addEventHandler(c,"onblur",function(){bt.unregister(a)});if(c==p.activeElement){bt.register(a)}});var bL=new M("active",function(c){var a=arguments;h.CSS.addEventHandler(c,"onmousedown",function(){bL.register(a)})});y(p,"onmouseup",function(){var c=bL.instances;for(var a in c)bL.unregister(c[a])});var dh=/^url\s*\(\s*([^)]*)\)$/;var di={before0:"beforeBegin",before1:"afterBegin",after0:"afterEnd",after1:"beforeEnd"};var R=h.PseudoElement=u.extend({constructor:function(j,i,g){this.position=i;var f=g.match(R.CONTENT),d,c;if(f){f=f[1];d=f.split(/\s+/);for(var a=0;(c=d[a]);a++){d[a]=/^attr/.test(c)?{attr:c.slice(5,-1)}:c.charAt(0)==="'"?bp(c):bd(c)}f=d}this.content=f;this.base(j,bd(g))},init:function(){this.match=J(this.selector);for(var c=0;c<this.match.length;c++){var a=this.match[c].runtimeStyle;if(!a[this.position])a[this.position]={cssText:""};a[this.position].cssText+=";"+this.cssText;if(this.content!=null)a[this.position].content=this.content}},create:function(n){var o=n.runtimeStyle[this.position];if(o){var k=[].concat(o.content||"");for(var l=0;l<k.length;l++){if(typeof k[l]=="object"){k[l]=n.getAttribute(k[l].attr)}}k=k.join("");var m=k.match(dh);var j="overflow:hidden;"+o.cssText.replace(/'/g,'"');var i=di[this.position+Number(n.canHaveChildren)];var g='ie7_pseudo'+R.count++;n.insertAdjacentHTML(i,H(R.ANON,this.className,g,j,m?"":k));if(m){var f=bp(m[1]);var d=p.getElementById(g);d.src=f;bs(d,"crop");var c=n.currentStyle.styleFloat!=="none";if(d.currentStyle.display==="inline"||c){if(t<7&&c&&n.canHaveChildren){n.runtimeStyle.display="inline";n.runtimeStyle.position="relative";d.runtimeStyle.position="absolute"}d.style.display="inline-block";if(n.currentStyle.styleFloat!=="none"){d.style.pixelWidth=n.offsetWidth}var a=new Image;a.onload=function(){d.style.pixelWidth=this.width;d.style.pixelHeight=Math.max(this.height,d.offsetHeight)};a.src=f}}n.runtimeStyle[this.position]=null}},recalc:function(){if(this.content==null)return;for(var a=0;a<this.match.length;a++){this.create(this.match[a])}},toString:function(){return"."+this.className+"{display:inline}"}},{CONTENT:/content\s*:\s*([^;]*)(;|$)/,ANON:"<ie7:! class='ie7_anon %1' id=%2 style='%3'>%4</ie7:!>",MATCH:/(.*):(before|after).*/,count:0});h._getLang=function(c){var a="";while(c&&c.nodeType===1){a=c.lang||c.getAttribute("lang")||"";if(a)break;c=c.parentNode}return a};T=O(T,{":lang\\(([^)]+)\\)":"((ii=IE7._getLang(e))==='$1'||ii.indexOf('$1-')===0)&&"})}var dj=/^(submit|reset|button)$/;h.HTML.addRecalc("button,input",function(c){if(c.nodeName==="BUTTON"){var a=c.outerHTML.match(/ value="([^"]*)"/i);c.runtimeStyle.value=a?a[1]:""}if(c.type==="submit"){y(c,"onclick",function(){c.runtimeStyle.clicked=true;setTimeout("document.all."+c.uniqueID+".runtimeStyle.clicked=false",1)})}});h.HTML.addRecalc("form",function(d){y(d,"onsubmit",function(){for(var c,a=0;c=d[a];a++){if(dj.test(c.type)&&!c.disabled&&!c.runtimeStyle.clicked){c.disabled=true;setTimeout("document.all."+c.uniqueID+".disabled=false",1)}else if(c.nodeName==="BUTTON"&&c.type==="submit"){setTimeout("document.all."+c.uniqueID+".value='"+c.value+"'",1);c.value=c.runtimeStyle.value}}})});h.HTML.addRecalc("img",function(a){if(a.alt&&!a.title)a.title=""});if(t<8){h.CSS.addRecalc("border-spacing",bg,function(a){if(a.currentStyle.borderCollapse!=="collapse"){a.cellSpacing=C(a,a.currentStyle["ie7-border-spacing"].split(" ")[0])}});h.CSS.addRecalc("box-sizing","content-box",h.Layout.boxSizing);h.CSS.addRecalc("box-sizing","border-box",h.Layout.borderBox)}if(t<8){var dk=/^image/i;h.HTML.addRecalc("object",function(a){if(dk.test(a.type)){a.body.style.cssText="margin:0;padding:0;border:none;overflow:hidden";return a}})}var bM="!IE7._a(e,'next')&&",cs=bM.replace("next","previous");if(h.CSS.pseudoClasses)h.CSS.pseudoClasses+="|";h.CSS.pseudoClasses+="(?:first|last|only)\\-(?:child|of\\-type)|empty|root|target|"+("not|nth\\-child|nth\\-last\\-child|nth\\-of\\-type|nth\\-last\\-of\\-type".split("|").join(bK+"|")+bK);var bN=new M("checked",function(c){if(typeof c.checked!=="boolean")return;var a=arguments;h.CSS.addEventHandler(c,"onpropertychange",function(){if(event.propertyName==="checked"){if(c.checked===true)bN.register(a);else bN.unregister(a)}});if(c.checked===true)bN.register(a)}),bO=new M("enabled",function(c){if(typeof c.disabled!=="boolean")return;var a=arguments;h.CSS.addEventHandler(c,"onpropertychange",function(){if(event.propertyName==="disabled"){if(c.disabled===false)bO.register(a);else bO.unregister(a)}});if(c.disabled===false)bO.register(a)}),bP=new M("disabled",function(c){if(typeof c.disabled!=="boolean")return;var a=arguments;h.CSS.addEventHandler(c,"onpropertychange",function(){if(event.propertyName==="disabled"){if(c.disabled===true)bP.register(a);else bP.unregister(a)}});if(c.disabled===true)bP.register(a)}),bQ=new M("indeterminate",function(c){if(typeof c.indeterminate!=="boolean")return;var a=arguments;h.CSS.addEventHandler(c,"onpropertychange",function(){if(event.propertyName==="indeterminate"){if(c.indeterminate===true)bQ.register(a);else bQ.unregister(a)}});h.CSS.addEventHandler(c,"onclick",function(){bQ.unregister(a)})}),bR=new M("target",function(c){var a=arguments;if(!c.tabIndex)c.tabIndex=0;h.CSS.addEventHandler(p,"onpropertychange",function(){if(event.propertyName==="activeElement"){if(c.id&&c.id===location.hash.slice(1))bR.register(a);else bR.unregister(a)}});if(c.id&&c.id===location.hash.slice(1))bR.register(a)}),ct=1,bu={_4:1};h._b=function(l,m,j){var i=l.parentNode;if(!i||i.nodeType!==1)return NaN;var g=j?l.nodeName:"";if(g==="TR"&&l.sectionRowIndex>=0){var c=l.sectionRowIndex;return m?l.parentNode.rows.length-c+1:c}if((g==="TD"||g==="TH")&&l.cellIndex>=0){c=l.cellIndex;return m?l.parentNode.cells.length-c+1:c}if(bu._4!==ct){bu={_4:ct}}var f=(i.uniqueID)+"-"+g,d=bu[f];if(!d){d={};var c=0,a=i.firstChild;while(a){if(j?a.nodeName===g:a.nodeName>"@"){d[a.uniqueID]=++c}a=a.nextSibling}d.length=c;bu[f]=d}c=d[l.uniqueID];return m?d.length-c+1:c};h._c=function(a){a=a.firstChild;while(a){if(a.nodeType===3||a.nodeName>"@")return false;a=a.nextSibling}return true};h._a=function(d,c){var a=d.nodeName;c+="Sibling";do{d=d[c];if(d&&d.nodeName===a)break}while(d);return d};var dl={"+":1,"-":-1},dm=/ /g;T=O(O({":nth(-last)?-(?:child|(of-type))\\((<#nth_arg>)\\)(<#filter>)?":function(m,j,i,g,f){g=g.replace(dm,"");var d="IE7._b(e,"+!!j+","+!!i+")";if(g==="even")g="2n";else if(g==="odd")g="2n+1";else if(!isNaN(g))g="0n"+~~g;g=g.split("n");var c=~~(dl[g[0]]||g[0]||1),b=~~g[1];if(c===0){var a=d+"==="+b}else{a="((ii="+d+")-("+b+"))%"+c+"===0&&ii"+(c<0?"<":">")+"="+b}return this.parse(f)+a+"&&"},"<#negation>":function(c,a){if(/:not/i.test(a))bv();if(/^[#.:\[]/.test(a)){a="*"+a}return"!("+D.parse(a).slice(3,-2)+")&&"}},T),{":checked":"e.checked===true&&",":disabled":"e.disabled===true&&",":enabled":"e.disabled===false&&",":last-child":"!"+bE+"&&",":only-child":"!"+ck+"&&!"+bE+"&&",":first-of-type":cs,":last-of-type":bM,":only-of-type":cs+bM,":empty":"IE7._c(e)&&",":root":"e==R&&",":target":"H&&"+cn+"===H&&"});var dn="article,aside,audio,canvas,details,figcaption,figure,footer,header,hgroup,mark,menu,meter,nav,output,progress,section,summary,time,video".split(",");for(var cu=0,cv;cv=dn[cu];cu++)p.createElement(cv);U+="datalist{display:none}details{padding-left:40px;display:block;margin:1em 0}meter,progress{vertical-align:-0.2em;width:5em;height:1em;display:inline-block}progress{width:10em;}article,aside,figcaption,footer,header,hgroup,summary,section,nav{display:block;margin:1em 0}figure{margin:1em 40px;display:block}mark{background:yellow}";h.CSS.addFix(/\bopacity\s*:\s*([\d.]+)/,function(c,a){return"zoom:1;filter:Alpha(opacity="+((a*100)||1)+")"});var D,J=(function(){var o0=/^[>+~]/,bw=false;function dp(f,d,c){f=bZ(f);if(!d)d=p;var a=d;bw=o0.test(f);if(bw){d=d.parentNode;f="*"+f}try{return n.create(f,bw)(d,c?null:[],a)}catch(ex){return c?null:[]}};var dq=/^(\\.|[' >+~#.\[\]:*(),\w-\^|$=]|[^\x00-\xa0])+$/,dE=/^(href|src)$/,cw={"class":"className","for":"htmlFor"},dF=/\sie7_\w+/g,dr=/^(action|cite|codebase|data|dynsrc|href|longdesc|lowsrc|src|usemap|url)$/i;h._0=function(f,d){if(f.getAttributeNode){var c=f.getAttributeNode(d)}d=cw[d.toLowerCase()]||d;if(!c)c=f.attributes[d];var a=c&&c.specified;if(f[d]&&typeof f[d]=="boolean")return d.toLowerCase();if((a&&dr.test(d))||(!c&&E)||d==="value"||d==="type"){return f.getAttribute(d,2)}if(d==="style")return f.style.cssText.toLowerCase()||null;return a?String(c.nodeValue):null};var cx="colSpan,rowSpan,vAlign,dateTime,accessKey,tabIndex,encType,maxLength,readOnly,longDesc";O(cw,cO(cx.toLowerCase().split(","),cx.split(",")));h._1=function(c,a){a+="Sibling";do{c=c[a];if(c&&c.nodeName>"@")break}while(c);return c};var ds=/(^|[, >+~])([#.:\[])/g,dG=/\)\{/g,dt=/,/,dH=/^['"]/,du=/\\([\da-f]{2,2})/gi,dI=/last/i;h._d=function(f,d){var c=f.all[d]||null;if(!c||(c.nodeType&&h._0(c,"id")===d))return c;for(var a=0;a<c.length;a++){if(h._0(c[a],"id")===d)return c[a]}return null};var bb=G.extend({dictionary:new cM({ident:/\-?(\\.|[_a-z]|[^\x00-\xa0])(\\.|[\w-]|[^\x00-\xa0])*/,combinator:/[\s>+~]/,operator:/[\^~|$*]?=/,nth_arg:/[+-]?\d+|[+-]?\d*n(?:\s*[+-]\s*\d+)?|even|odd/,tag:/\*|<#ident>/,id:/#(<#ident>)/,'class':/\.(<#ident>)/,pseudo:/\:([\w-]+)(?:\(([^)]+)\))?/,attr:/\[(<#ident>)(?:(<#operator>)((?:\\.|[^\[\]#.:])+))?\]/,negation:/:not\((<#tag>|<#id>|<#class>|<#attr>|<#pseudo>)\)/,sequence:/(\\.|[~*]=|\+\d|\+?\d*n\s*\+\s*\d|[^\s>+~,\*])+/,filter:/[#.:\[]<#sequence>/,selector:/[^>+~](\\.|[^,])*?/,grammar:/^(<#selector>)((,<#selector>)*)$/}),ignoreCase:true}),dv=new bb({"\\\\.|[~*]\\s+=|\\+\\s+\\d":G.IGNORE,"\\[\\s+":"[","\\(\\s+":"(","\\s+\\)":")","\\s+\\]":"]","\\s*([,>+~]|<#operator>)\\s*":"$1","\\s+$":"","\\s+":" "});function dw(a){a=dv.parse(a.replace(du,"\\x$1")).replace(bz,"$1").replace(ds,"$1*$2");if(!dq.test(a))bv();return a};function dJ(a){return a.replace(cb,dx)};function dx(c,a){return W[a]};var dy=/\{/g,dz=/\\{/g;function bS(a){return Array((a.replace(dz,"").match(dy)||"").length+1).join("}")};T=new bb(T);var v=/:target/i,Z=/:root/i;function S(c){var a="";if(Z.test(c))a+=",R=d.documentElement";if(v.test(c))a+=",H=d.location;H=H&&H.hash.replace('#','')";if(a||c.indexOf("#")!==-1){a=",t=c.nodeType,d=t===9?c:c.ownerDocument||(c.document||c).parentWindow.document"+a}return"var ii"+a+";"};var ba={" ":";while(e!=s&&(e=e.parentNode)&&e.nodeType===1){",">":".parentElement;if(e){","+":";while((e=e.previousSibling)&&!("+cl+"))continue;if(e){","~":";while((e=e.previousSibling)){"+cm},K=/\be\b/g;D=new bb({"(?:(<#selector>)(<#combinator>))?(<#tag>)(<#filter>)?$":function(j,i,g,f,d){var c="";if(f!=="*"){var a=f.toUpperCase();c+="if(e.nodeName==='"+a+(a===f?"":"'||e.nodeName==='"+f)+"'){"}if(d){c+="if("+T.parse(d).slice(0,-2)+"){"}c=c.replace(K,"e"+this.index);if(g){c+="var e=e"+(this.index++)+ba[g];c=c.replace(K,"e"+this.index)}if(i){c+=this.parse(i)}return c}});var L="e0=IE7._d(d,'%1');if(e0){",z="var n=c.getElementsByTagName('%1');",w="if(r==null)return e0;r[k++]=e0;",r=1,A=new bb({"^((?:<#selector>)?(?:<#combinator>))(<#tag>)(<#filter>)?$":true}),s={},q=new bb({"^(<#tag>)#(<#ident>)(<#filter>)?( [^,]*)?$":function(j,i,g,f,d){var c=H(L,g),a="}";if(f){c+=D.parse(i+f);a=bS(c)}if(d){c+="s=c=e0;"+n.parse("*"+d)}else{c+=w}return c+a},"^([^#,]+)#(<#ident>)(<#filter>)?$":function(g,f,d,c){var a=H(L,d);if(f==="*"){a+=w}else{a+=D.parse(f+c)+w+"break"}return a+bS(a)},"^.*$":""}),n=new bb({"<#grammar>":function(k,l,m){if(!this.groups)this.groups=[];var j=A.exec(" "+l);if(!j)bv();this.groups.push(j.slice(1));if(m){return this.parse(m.replace(dt,""))}var i=this.groups,g=i[0][r];for(var c=1;j=i[c];c++){if(g!==j[r]){g="*";break}}var f="",d=w+"continue filtering;";for(var c=0;j=i[c];c++){D.index=0;if(g!=="*")j[r]="*";j=j.join("");if(j===" *"){f=d;break}else{j=D.parse(j);if(bw)j+="if(e"+D.index+"==s){";f+=j+d+bS(j)}}var a=g==="*";return(a?"var n=c.all;":H(z,g))+"filtering:while((e0=n[i++]))"+(a?cm.replace(K,"e0"):"{")+f+"}"},"^.*$":bv}),o=/\&\&(e\d+)\.nodeType===1(\)\{\s*if\(\1\.nodeName=)/g;n.create=function(d){if(!s[d]){d=dw(d);this.groups=null;D.index=0;var c=this.parse(d);this.groups=null;D.index=0;if(d.indexOf("#")!==-1){var a=q.parse(d);if(a){c="if(t===1||t===11|!c.getElementById){"+c+"}else{"+a+"}"}}c=c.replace(o,"$2");c=S(d)+bd(c);s[d]=new Function("return function(c,r,s){var i=0,k=0,e0;"+c+"return r}")()}return s[d]};return dp})();function bv(){throw new SyntaxError("Invalid selector.");};h.loaded=true;(function(){try{if(!p.body)throw"continue";bx.doScroll("left")}catch(ex){setTimeout(arguments.callee,1);return}try{eval(bU.innerHTML)}catch(ex){}if(typeof IE7_PNG_SUFFIX=="object"){bh=IE7_PNG_SUFFIX}else{bh=new RegExp(bY(N.IE7_PNG_SUFFIX||"-trans.png")+"(\\?.*)?$","i")}B=p.body;x=E?B:bx;B.className+=" ie7_body";bx.className+=" ie7_html";if(E)dc();h.CSS.init();h.HTML.init();h.HTML.apply();h.CSS.apply();h.recalc()})()})(this,document);
@@ -0,0 +1,1012 @@
1
+ // Backbone.js 0.3.3
2
+ // (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
3
+ // Backbone may be freely distributed under the MIT license.
4
+ // For all details and documentation:
5
+ // http://documentcloud.github.com/backbone
6
+
7
+ (function(){
8
+
9
+ // Initial Setup
10
+ // -------------
11
+
12
+ // The top-level namespace. All public Backbone classes and modules will
13
+ // be attached to this. Exported for both CommonJS and the browser.
14
+ var Backbone;
15
+ if (typeof exports !== 'undefined') {
16
+ Backbone = exports;
17
+ } else {
18
+ Backbone = this.Backbone = {};
19
+ }
20
+
21
+ // Current version of the library. Keep in sync with `package.json`.
22
+ Backbone.VERSION = '0.3.3';
23
+
24
+ // Require Underscore, if we're on the server, and it's not already present.
25
+ var _ = this._;
26
+ if (!_ && (typeof require !== 'undefined')) _ = require("underscore")._;
27
+
28
+ // For Backbone's purposes, either jQuery or Zepto owns the `$` variable.
29
+ var $ = this.jQuery || this.Zepto;
30
+
31
+ // Turn on `emulateHTTP` to use support legacy HTTP servers. Setting this option will
32
+ // fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and set a
33
+ // `X-Http-Method-Override` header.
34
+ Backbone.emulateHTTP = false;
35
+
36
+ // Turn on `emulateJSON` to support legacy servers that can't deal with direct
37
+ // `application/json` requests ... will encode the body as
38
+ // `application/x-www-form-urlencoded` instead and will send the model in a
39
+ // form param named `model`.
40
+ Backbone.emulateJSON = false;
41
+
42
+ // Backbone.Events
43
+ // -----------------
44
+
45
+ // A module that can be mixed in to *any object* in order to provide it with
46
+ // custom events. You may `bind` or `unbind` a callback function to an event;
47
+ // `trigger`-ing an event fires all callbacks in succession.
48
+ //
49
+ // var object = {};
50
+ // _.extend(object, Backbone.Events);
51
+ // object.bind('expand', function(){ alert('expanded'); });
52
+ // object.trigger('expand');
53
+ //
54
+ Backbone.Events = {
55
+
56
+ // Bind an event, specified by a string name, `ev`, to a `callback` function.
57
+ // Passing `"all"` will bind the callback to all events fired.
58
+ bind : function(ev, callback) {
59
+ var calls = this._callbacks || (this._callbacks = {});
60
+ var list = this._callbacks[ev] || (this._callbacks[ev] = []);
61
+ list.push(callback);
62
+ return this;
63
+ },
64
+
65
+ // Remove one or many callbacks. If `callback` is null, removes all
66
+ // callbacks for the event. If `ev` is null, removes all bound callbacks
67
+ // for all events.
68
+ unbind : function(ev, callback) {
69
+ var calls;
70
+ if (!ev) {
71
+ this._callbacks = {};
72
+ } else if (calls = this._callbacks) {
73
+ if (!callback) {
74
+ calls[ev] = [];
75
+ } else {
76
+ var list = calls[ev];
77
+ if (!list) return this;
78
+ for (var i = 0, l = list.length; i < l; i++) {
79
+ if (callback === list[i]) {
80
+ list.splice(i, 1);
81
+ break;
82
+ }
83
+ }
84
+ }
85
+ }
86
+ return this;
87
+ },
88
+
89
+ // Trigger an event, firing all bound callbacks. Callbacks are passed the
90
+ // same arguments as `trigger` is, apart from the event name.
91
+ // Listening for `"all"` passes the true event name as the first argument.
92
+ trigger : function(ev) {
93
+ var list, calls, i, l;
94
+ if (!(calls = this._callbacks)) return this;
95
+ if (list = calls[ev]) {
96
+ for (i = 0, l = list.length; i < l; i++) {
97
+ list[i].apply(this, Array.prototype.slice.call(arguments, 1));
98
+ }
99
+ }
100
+ if (list = calls['all']) {
101
+ for (i = 0, l = list.length; i < l; i++) {
102
+ list[i].apply(this, arguments);
103
+ }
104
+ }
105
+ return this;
106
+ }
107
+
108
+ };
109
+
110
+ // Backbone.Model
111
+ // --------------
112
+
113
+ // Create a new model, with defined attributes. A client id (`cid`)
114
+ // is automatically generated and assigned for you.
115
+ Backbone.Model = function(attributes, options) {
116
+ attributes || (attributes = {});
117
+ if (this.defaults) attributes = _.extend({}, this.defaults, attributes);
118
+ this.attributes = {};
119
+ this._escapedAttributes = {};
120
+ this.cid = _.uniqueId('c');
121
+ this.set(attributes, {silent : true});
122
+ this._previousAttributes = _.clone(this.attributes);
123
+ if (options && options.collection) this.collection = options.collection;
124
+ this.initialize(attributes, options);
125
+ };
126
+
127
+ // Attach all inheritable methods to the Model prototype.
128
+ _.extend(Backbone.Model.prototype, Backbone.Events, {
129
+
130
+ // A snapshot of the model's previous attributes, taken immediately
131
+ // after the last `"change"` event was fired.
132
+ _previousAttributes : null,
133
+
134
+ // Has the item been changed since the last `"change"` event?
135
+ _changed : false,
136
+
137
+ // Initialize is an empty function by default. Override it with your own
138
+ // initialization logic.
139
+ initialize : function(){},
140
+
141
+ // Return a copy of the model's `attributes` object.
142
+ toJSON : function() {
143
+ return _.clone(this.attributes);
144
+ },
145
+
146
+ // Get the value of an attribute.
147
+ get : function(attr) {
148
+ return this.attributes[attr];
149
+ },
150
+
151
+ // Get the HTML-escaped value of an attribute.
152
+ escape : function(attr) {
153
+ var html;
154
+ if (html = this._escapedAttributes[attr]) return html;
155
+ var val = this.attributes[attr];
156
+ return this._escapedAttributes[attr] = escapeHTML(val == null ? '' : val);
157
+ },
158
+
159
+ // Set a hash of model attributes on the object, firing `"change"` unless you
160
+ // choose to silence it.
161
+ set : function(attrs, options) {
162
+
163
+ // Extract attributes and options.
164
+ options || (options = {});
165
+ if (!attrs) return this;
166
+ if (attrs.attributes) attrs = attrs.attributes;
167
+ var now = this.attributes, escaped = this._escapedAttributes;
168
+
169
+ // Run validation.
170
+ if (!options.silent && this.validate && !this._performValidation(attrs, options)) return false;
171
+
172
+ // Check for changes of `id`.
173
+ if ('id' in attrs) this.id = attrs.id;
174
+
175
+ // Update attributes.
176
+ for (var attr in attrs) {
177
+ var val = attrs[attr];
178
+ if (!_.isEqual(now[attr], val)) {
179
+ now[attr] = val;
180
+ delete escaped[attr];
181
+ if (!options.silent) {
182
+ this._changed = true;
183
+ this.trigger('change:' + attr, this, val, options);
184
+ }
185
+ }
186
+ }
187
+
188
+ // Fire the `"change"` event, if the model has been changed.
189
+ if (!options.silent && this._changed) this.change(options);
190
+ return this;
191
+ },
192
+
193
+ // Remove an attribute from the model, firing `"change"` unless you choose
194
+ // to silence it.
195
+ unset : function(attr, options) {
196
+ options || (options = {});
197
+ var value = this.attributes[attr];
198
+
199
+ // Run validation.
200
+ var validObj = {};
201
+ validObj[attr] = void 0;
202
+ if (!options.silent && this.validate && !this._performValidation(validObj, options)) return false;
203
+
204
+ // Remove the attribute.
205
+ delete this.attributes[attr];
206
+ delete this._escapedAttributes[attr];
207
+ if (!options.silent) {
208
+ this._changed = true;
209
+ this.trigger('change:' + attr, this, void 0, options);
210
+ this.change(options);
211
+ }
212
+ return this;
213
+ },
214
+
215
+ // Clear all attributes on the model, firing `"change"` unless you choose
216
+ // to silence it.
217
+ clear : function(options) {
218
+ options || (options = {});
219
+ var old = this.attributes;
220
+
221
+ // Run validation.
222
+ var validObj = {};
223
+ for (attr in old) validObj[attr] = void 0;
224
+ if (!options.silent && this.validate && !this._performValidation(validObj, options)) return false;
225
+
226
+ this.attributes = {};
227
+ this._escapedAttributes = {};
228
+ if (!options.silent) {
229
+ this._changed = true;
230
+ for (attr in old) {
231
+ this.trigger('change:' + attr, this, void 0, options);
232
+ }
233
+ this.change(options);
234
+ }
235
+ return this;
236
+ },
237
+
238
+ // Fetch the model from the server. If the server's representation of the
239
+ // model differs from its current attributes, they will be overriden,
240
+ // triggering a `"change"` event.
241
+ fetch : function(options) {
242
+ options || (options = {});
243
+ var model = this;
244
+ var success = function(resp) {
245
+ if (!model.set(model.parse(resp), options)) return false;
246
+ if (options.success) options.success(model, resp);
247
+ };
248
+ var error = wrapError(options.error, model, options);
249
+ (this.sync || Backbone.sync)('read', this, success, error);
250
+ return this;
251
+ },
252
+
253
+ // Set a hash of model attributes, and sync the model to the server.
254
+ // If the server returns an attributes hash that differs, the model's
255
+ // state will be `set` again.
256
+ save : function(attrs, options) {
257
+ options || (options = {});
258
+ if (attrs && !this.set(attrs, options)) return false;
259
+ var model = this;
260
+ var success = function(resp) {
261
+ if (!model.set(model.parse(resp), options)) return false;
262
+ if (options.success) options.success(model, resp);
263
+ };
264
+ var error = wrapError(options.error, model, options);
265
+ var method = this.isNew() ? 'create' : 'update';
266
+ (this.sync || Backbone.sync)(method, this, success, error);
267
+ return this;
268
+ },
269
+
270
+ // Destroy this model on the server. Upon success, the model is removed
271
+ // from its collection, if it has one.
272
+ destroy : function(options) {
273
+ options || (options = {});
274
+ var model = this;
275
+ var success = function(resp) {
276
+ if (model.collection) model.collection.remove(model);
277
+ if (options.success) options.success(model, resp);
278
+ };
279
+ var error = wrapError(options.error, model, options);
280
+ (this.sync || Backbone.sync)('delete', this, success, error);
281
+ return this;
282
+ },
283
+
284
+ // Default URL for the model's representation on the server -- if you're
285
+ // using Backbone's restful methods, override this to change the endpoint
286
+ // that will be called.
287
+ url : function() {
288
+ var base = getUrl(this.collection);
289
+ if (this.isNew()) return base;
290
+ return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + this.id;
291
+ },
292
+
293
+ // **parse** converts a response into the hash of attributes to be `set` on
294
+ // the model. The default implementation is just to pass the response along.
295
+ parse : function(resp) {
296
+ return resp;
297
+ },
298
+
299
+ // Create a new model with identical attributes to this one.
300
+ clone : function() {
301
+ return new this.constructor(this);
302
+ },
303
+
304
+ // A model is new if it has never been saved to the server, and has a negative
305
+ // ID.
306
+ isNew : function() {
307
+ return !this.id;
308
+ },
309
+
310
+ // Call this method to manually fire a `change` event for this model.
311
+ // Calling this will cause all objects observing the model to update.
312
+ change : function(options) {
313
+ this.trigger('change', this, options);
314
+ this._previousAttributes = _.clone(this.attributes);
315
+ this._changed = false;
316
+ },
317
+
318
+ // Determine if the model has changed since the last `"change"` event.
319
+ // If you specify an attribute name, determine if that attribute has changed.
320
+ hasChanged : function(attr) {
321
+ if (attr) return this._previousAttributes[attr] != this.attributes[attr];
322
+ return this._changed;
323
+ },
324
+
325
+ // Return an object containing all the attributes that have changed, or false
326
+ // if there are no changed attributes. Useful for determining what parts of a
327
+ // view need to be updated and/or what attributes need to be persisted to
328
+ // the server.
329
+ changedAttributes : function(now) {
330
+ now || (now = this.attributes);
331
+ var old = this._previousAttributes;
332
+ var changed = false;
333
+ for (var attr in now) {
334
+ if (!_.isEqual(old[attr], now[attr])) {
335
+ changed = changed || {};
336
+ changed[attr] = now[attr];
337
+ }
338
+ }
339
+ return changed;
340
+ },
341
+
342
+ // Get the previous value of an attribute, recorded at the time the last
343
+ // `"change"` event was fired.
344
+ previous : function(attr) {
345
+ if (!attr || !this._previousAttributes) return null;
346
+ return this._previousAttributes[attr];
347
+ },
348
+
349
+ // Get all of the attributes of the model at the time of the previous
350
+ // `"change"` event.
351
+ previousAttributes : function() {
352
+ return _.clone(this._previousAttributes);
353
+ },
354
+
355
+ // Run validation against a set of incoming attributes, returning `true`
356
+ // if all is well. If a specific `error` callback has been passed,
357
+ // call that instead of firing the general `"error"` event.
358
+ _performValidation : function(attrs, options) {
359
+ var error = this.validate(attrs);
360
+ if (error) {
361
+ if (options.error) {
362
+ options.error(this, error);
363
+ } else {
364
+ this.trigger('error', this, error, options);
365
+ }
366
+ return false;
367
+ }
368
+ return true;
369
+ }
370
+
371
+ });
372
+
373
+ // Backbone.Collection
374
+ // -------------------
375
+
376
+ // Provides a standard collection class for our sets of models, ordered
377
+ // or unordered. If a `comparator` is specified, the Collection will maintain
378
+ // its models in sort order, as they're added and removed.
379
+ Backbone.Collection = function(models, options) {
380
+ options || (options = {});
381
+ if (options.comparator) {
382
+ this.comparator = options.comparator;
383
+ delete options.comparator;
384
+ }
385
+ this._boundOnModelEvent = _.bind(this._onModelEvent, this);
386
+ this._reset();
387
+ if (models) this.refresh(models, {silent: true});
388
+ this.initialize(models, options);
389
+ };
390
+
391
+ // Define the Collection's inheritable methods.
392
+ _.extend(Backbone.Collection.prototype, Backbone.Events, {
393
+
394
+ // The default model for a collection is just a **Backbone.Model**.
395
+ // This should be overridden in most cases.
396
+ model : Backbone.Model,
397
+
398
+ // Initialize is an empty function by default. Override it with your own
399
+ // initialization logic.
400
+ initialize : function(){},
401
+
402
+ // The JSON representation of a Collection is an array of the
403
+ // models' attributes.
404
+ toJSON : function() {
405
+ return this.map(function(model){ return model.toJSON(); });
406
+ },
407
+
408
+ // Add a model, or list of models to the set. Pass **silent** to avoid
409
+ // firing the `added` event for every new model.
410
+ add : function(models, options) {
411
+ if (_.isArray(models)) {
412
+ for (var i = 0, l = models.length; i < l; i++) {
413
+ this._add(models[i], options);
414
+ }
415
+ } else {
416
+ this._add(models, options);
417
+ }
418
+ return this;
419
+ },
420
+
421
+ // Remove a model, or a list of models from the set. Pass silent to avoid
422
+ // firing the `removed` event for every model removed.
423
+ remove : function(models, options) {
424
+ if (_.isArray(models)) {
425
+ for (var i = 0, l = models.length; i < l; i++) {
426
+ this._remove(models[i], options);
427
+ }
428
+ } else {
429
+ this._remove(models, options);
430
+ }
431
+ return this;
432
+ },
433
+
434
+ // Get a model from the set by id.
435
+ get : function(id) {
436
+ if (id == null) return null;
437
+ return this._byId[id.id != null ? id.id : id];
438
+ },
439
+
440
+ // Get a model from the set by client id.
441
+ getByCid : function(cid) {
442
+ return cid && this._byCid[cid.cid || cid];
443
+ },
444
+
445
+ // Get the model at the given index.
446
+ at: function(index) {
447
+ return this.models[index];
448
+ },
449
+
450
+ // Force the collection to re-sort itself. You don't need to call this under normal
451
+ // circumstances, as the set will maintain sort order as each item is added.
452
+ sort : function(options) {
453
+ options || (options = {});
454
+ if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
455
+ this.models = this.sortBy(this.comparator);
456
+ if (!options.silent) this.trigger('refresh', this, options);
457
+ return this;
458
+ },
459
+
460
+ // Pluck an attribute from each model in the collection.
461
+ pluck : function(attr) {
462
+ return _.map(this.models, function(model){ return model.get(attr); });
463
+ },
464
+
465
+ // When you have more items than you want to add or remove individually,
466
+ // you can refresh the entire set with a new list of models, without firing
467
+ // any `added` or `removed` events. Fires `refresh` when finished.
468
+ refresh : function(models, options) {
469
+ models || (models = []);
470
+ options || (options = {});
471
+ this._reset();
472
+ this.add(models, {silent: true});
473
+ if (!options.silent) this.trigger('refresh', this, options);
474
+ return this;
475
+ },
476
+
477
+ // Fetch the default set of models for this collection, refreshing the
478
+ // collection when they arrive.
479
+ fetch : function(options) {
480
+ options || (options = {});
481
+ var collection = this;
482
+ var success = function(resp) {
483
+ collection.refresh(collection.parse(resp));
484
+ if (options.success) options.success(collection, resp);
485
+ };
486
+ var error = wrapError(options.error, collection, options);
487
+ (this.sync || Backbone.sync)('read', this, success, error);
488
+ return this;
489
+ },
490
+
491
+ // Create a new instance of a model in this collection. After the model
492
+ // has been created on the server, it will be added to the collection.
493
+ create : function(model, options) {
494
+ var coll = this;
495
+ options || (options = {});
496
+ if (!(model instanceof Backbone.Model)) {
497
+ model = new this.model(model, {collection: coll});
498
+ } else {
499
+ model.collection = coll;
500
+ }
501
+ var success = function(nextModel, resp) {
502
+ coll.add(nextModel);
503
+ if (options.success) options.success(nextModel, resp);
504
+ };
505
+ return model.save(null, {success : success, error : options.error});
506
+ },
507
+
508
+ // **parse** converts a response into a list of models to be added to the
509
+ // collection. The default implementation is just to pass it through.
510
+ parse : function(resp) {
511
+ return resp;
512
+ },
513
+
514
+ // Proxy to _'s chain. Can't be proxied the same way the rest of the
515
+ // underscore methods are proxied because it relies on the underscore
516
+ // constructor.
517
+ chain: function () {
518
+ return _(this.models).chain();
519
+ },
520
+
521
+ // Reset all internal state. Called when the collection is refreshed.
522
+ _reset : function(options) {
523
+ this.length = 0;
524
+ this.models = [];
525
+ this._byId = {};
526
+ this._byCid = {};
527
+ },
528
+
529
+ // Internal implementation of adding a single model to the set, updating
530
+ // hash indexes for `id` and `cid` lookups.
531
+ _add : function(model, options) {
532
+ options || (options = {});
533
+ if (!(model instanceof Backbone.Model)) {
534
+ model = new this.model(model, {collection: this});
535
+ }
536
+ var already = this.getByCid(model);
537
+ if (already) throw new Error(["Can't add the same model to a set twice", already.id]);
538
+ this._byId[model.id] = model;
539
+ this._byCid[model.cid] = model;
540
+ model.collection = this;
541
+ var index = this.comparator ? this.sortedIndex(model, this.comparator) : this.length;
542
+ this.models.splice(index, 0, model);
543
+ model.bind('all', this._boundOnModelEvent);
544
+ this.length++;
545
+ if (!options.silent) model.trigger('add', model, this, options);
546
+ return model;
547
+ },
548
+
549
+ // Internal implementation of removing a single model from the set, updating
550
+ // hash indexes for `id` and `cid` lookups.
551
+ _remove : function(model, options) {
552
+ options || (options = {});
553
+ model = this.getByCid(model) || this.get(model);
554
+ if (!model) return null;
555
+ delete this._byId[model.id];
556
+ delete this._byCid[model.cid];
557
+ delete model.collection;
558
+ this.models.splice(this.indexOf(model), 1);
559
+ this.length--;
560
+ if (!options.silent) model.trigger('remove', model, this, options);
561
+ model.unbind('all', this._boundOnModelEvent);
562
+ return model;
563
+ },
564
+
565
+ // Internal method called every time a model in the set fires an event.
566
+ // Sets need to update their indexes when models change ids. All other
567
+ // events simply proxy through.
568
+ _onModelEvent : function(ev, model) {
569
+ if (ev === 'change:id') {
570
+ delete this._byId[model.previous('id')];
571
+ this._byId[model.id] = model;
572
+ }
573
+ this.trigger.apply(this, arguments);
574
+ }
575
+
576
+ });
577
+
578
+ // Underscore methods that we want to implement on the Collection.
579
+ var methods = ['forEach', 'each', 'map', 'reduce', 'reduceRight', 'find', 'detect',
580
+ 'filter', 'select', 'reject', 'every', 'all', 'some', 'any', 'include',
581
+ 'invoke', 'max', 'min', 'sortBy', 'sortedIndex', 'toArray', 'size',
582
+ 'first', 'rest', 'last', 'without', 'indexOf', 'lastIndexOf', 'isEmpty'];
583
+
584
+ // Mix in each Underscore method as a proxy to `Collection#models`.
585
+ _.each(methods, function(method) {
586
+ Backbone.Collection.prototype[method] = function() {
587
+ return _[method].apply(_, [this.models].concat(_.toArray(arguments)));
588
+ };
589
+ });
590
+
591
+ // Backbone.Controller
592
+ // -------------------
593
+
594
+ // Controllers map faux-URLs to actions, and fire events when routes are
595
+ // matched. Creating a new one sets its `routes` hash, if not set statically.
596
+ Backbone.Controller = function(options) {
597
+ options || (options = {});
598
+ if (options.routes) this.routes = options.routes;
599
+ this._bindRoutes();
600
+ this.initialize(options);
601
+ };
602
+
603
+ // Cached regular expressions for matching named param parts and splatted
604
+ // parts of route strings.
605
+ var namedParam = /:([\w\d]+)/g;
606
+ var splatParam = /\*([\w\d]+)/g;
607
+
608
+ // Set up all inheritable **Backbone.Controller** properties and methods.
609
+ _.extend(Backbone.Controller.prototype, Backbone.Events, {
610
+
611
+ // Initialize is an empty function by default. Override it with your own
612
+ // initialization logic.
613
+ initialize : function(){},
614
+
615
+ // Manually bind a single named route to a callback. For example:
616
+ //
617
+ // this.route('search/:query/p:num', 'search', function(query, num) {
618
+ // ...
619
+ // });
620
+ //
621
+ route : function(route, name, callback) {
622
+ Backbone.history || (Backbone.history = new Backbone.History);
623
+ if (!_.isRegExp(route)) route = this._routeToRegExp(route);
624
+ Backbone.history.route(route, _.bind(function(fragment) {
625
+ var args = this._extractParameters(route, fragment);
626
+ callback.apply(this, args);
627
+ this.trigger.apply(this, ['route:' + name].concat(args));
628
+ }, this));
629
+ },
630
+
631
+ // Simple proxy to `Backbone.history` to save a fragment into the history,
632
+ // without triggering routes.
633
+ saveLocation : function(fragment) {
634
+ Backbone.history.saveLocation(fragment);
635
+ },
636
+
637
+ // Bind all defined routes to `Backbone.history`.
638
+ _bindRoutes : function() {
639
+ if (!this.routes) return;
640
+ for (var route in this.routes) {
641
+ var name = this.routes[route];
642
+ this.route(route, name, this[name]);
643
+ }
644
+ },
645
+
646
+ // Convert a route string into a regular expression, suitable for matching
647
+ // against the current location fragment.
648
+ _routeToRegExp : function(route) {
649
+ route = route.replace(namedParam, "([^\/]*)").replace(splatParam, "(.*?)");
650
+ return new RegExp('^' + route + '$');
651
+ },
652
+
653
+ // Given a route, and a URL fragment that it matches, return the array of
654
+ // extracted parameters.
655
+ _extractParameters : function(route, fragment) {
656
+ return route.exec(fragment).slice(1);
657
+ }
658
+
659
+ });
660
+
661
+ // Backbone.History
662
+ // ----------------
663
+
664
+ // Handles cross-browser history management, based on URL hashes. If the
665
+ // browser does not support `onhashchange`, falls back to polling.
666
+ Backbone.History = function() {
667
+ this.handlers = [];
668
+ this.fragment = this.getFragment();
669
+ _.bindAll(this, 'checkUrl');
670
+ };
671
+
672
+ // Cached regex for cleaning hashes.
673
+ var hashStrip = /^#*/;
674
+
675
+ // Set up all inheritable **Backbone.History** properties and methods.
676
+ _.extend(Backbone.History.prototype, {
677
+
678
+ // The default interval to poll for hash changes, if necessary, is
679
+ // twenty times a second.
680
+ interval: 50,
681
+
682
+ // Get the cross-browser normalized URL fragment.
683
+ getFragment : function(loc) {
684
+ return (loc || window.location).hash.replace(hashStrip, '');
685
+ },
686
+
687
+ // Start the hash change handling, returning `true` if the current URL matches
688
+ // an existing route, and `false` otherwise.
689
+ start : function() {
690
+ var docMode = document.documentMode;
691
+ var oldIE = ($.browser.msie && (!docMode || docMode <= 7));
692
+ if (oldIE) {
693
+ this.iframe = $('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
694
+ }
695
+ if ('onhashchange' in window && !oldIE) {
696
+ $(window).bind('hashchange', this.checkUrl);
697
+ } else {
698
+ setInterval(this.checkUrl, this.interval);
699
+ }
700
+ return this.loadUrl();
701
+ },
702
+
703
+ // Add a route to be tested when the hash changes. Routes are matched in the
704
+ // order they are added.
705
+ route : function(route, callback) {
706
+ this.handlers.push({route : route, callback : callback});
707
+ },
708
+
709
+ // Checks the current URL to see if it has changed, and if it has,
710
+ // calls `loadUrl`, normalizing across the hidden iframe.
711
+ checkUrl : function() {
712
+ var current = this.getFragment();
713
+ if (current == this.fragment && this.iframe) {
714
+ current = this.getFragment(this.iframe.location);
715
+ }
716
+ if (current == this.fragment ||
717
+ current == decodeURIComponent(this.fragment)) return false;
718
+ if (this.iframe) {
719
+ window.location.hash = this.iframe.location.hash = current;
720
+ }
721
+ this.loadUrl();
722
+ },
723
+
724
+ // Attempt to load the current URL fragment. If a route succeeds with a
725
+ // match, returns `true`. If no defined routes matches the fragment,
726
+ // returns `false`.
727
+ loadUrl : function() {
728
+ var fragment = this.fragment = this.getFragment();
729
+ var matched = _.any(this.handlers, function(handler) {
730
+ if (handler.route.test(fragment)) {
731
+ handler.callback(fragment);
732
+ return true;
733
+ }
734
+ });
735
+ return matched;
736
+ },
737
+
738
+ // Save a fragment into the hash history. You are responsible for properly
739
+ // URL-encoding the fragment in advance. This does not trigger
740
+ // a `hashchange` event.
741
+ saveLocation : function(fragment) {
742
+ fragment = (fragment || '').replace(hashStrip, '');
743
+ if (this.fragment == fragment) return;
744
+ window.location.hash = this.fragment = fragment;
745
+ if (this.iframe && (fragment != this.getFragment(this.iframe.location))) {
746
+ this.iframe.document.open().close();
747
+ this.iframe.location.hash = fragment;
748
+ }
749
+ }
750
+
751
+ });
752
+
753
+ // Backbone.View
754
+ // -------------
755
+
756
+ // Creating a Backbone.View creates its initial element outside of the DOM,
757
+ // if an existing element is not provided...
758
+ Backbone.View = function(options) {
759
+ this._configure(options || {});
760
+ this._ensureElement();
761
+ this.delegateEvents();
762
+ this.initialize(options);
763
+ };
764
+
765
+ // Element lookup, scoped to DOM elements within the current view.
766
+ // This should be prefered to global lookups, if you're dealing with
767
+ // a specific view.
768
+ var selectorDelegate = function(selector) {
769
+ return $(selector, this.el);
770
+ };
771
+
772
+ // Cached regex to split keys for `delegate`.
773
+ var eventSplitter = /^(\w+)\s*(.*)$/;
774
+
775
+ // Set up all inheritable **Backbone.View** properties and methods.
776
+ _.extend(Backbone.View.prototype, Backbone.Events, {
777
+
778
+ // The default `tagName` of a View's element is `"div"`.
779
+ tagName : 'div',
780
+
781
+ // Attach the `selectorDelegate` function as the `$` property.
782
+ $ : selectorDelegate,
783
+
784
+ // Initialize is an empty function by default. Override it with your own
785
+ // initialization logic.
786
+ initialize : function(){},
787
+
788
+ // **render** is the core function that your view should override, in order
789
+ // to populate its element (`this.el`), with the appropriate HTML. The
790
+ // convention is for **render** to always return `this`.
791
+ render : function() {
792
+ return this;
793
+ },
794
+
795
+ // Remove this view from the DOM. Note that the view isn't present in the
796
+ // DOM by default, so calling this method may be a no-op.
797
+ remove : function() {
798
+ $(this.el).remove();
799
+ return this;
800
+ },
801
+
802
+ // For small amounts of DOM Elements, where a full-blown template isn't
803
+ // needed, use **make** to manufacture elements, one at a time.
804
+ //
805
+ // var el = this.make('li', {'class': 'row'}, this.model.escape('title'));
806
+ //
807
+ make : function(tagName, attributes, content) {
808
+ var el = document.createElement(tagName);
809
+ if (attributes) $(el).attr(attributes);
810
+ if (content) $(el).html(content);
811
+ return el;
812
+ },
813
+
814
+ // Set callbacks, where `this.callbacks` is a hash of
815
+ //
816
+ // *{"event selector": "callback"}*
817
+ //
818
+ // {
819
+ // 'mousedown .title': 'edit',
820
+ // 'click .button': 'save'
821
+ // }
822
+ //
823
+ // pairs. Callbacks will be bound to the view, with `this` set properly.
824
+ // Uses event delegation for efficiency.
825
+ // Omitting the selector binds the event to `this.el`.
826
+ // This only works for delegate-able events: not `focus`, `blur`, and
827
+ // not `change`, `submit`, and `reset` in Internet Explorer.
828
+ delegateEvents : function(events) {
829
+ if (!(events || (events = this.events))) return;
830
+ $(this.el).unbind();
831
+ for (var key in events) {
832
+ var methodName = events[key];
833
+ var match = key.match(eventSplitter);
834
+ var eventName = match[1], selector = match[2];
835
+ var method = _.bind(this[methodName], this);
836
+ if (selector === '') {
837
+ $(this.el).bind(eventName, method);
838
+ } else {
839
+ $(this.el).delegate(selector, eventName, method);
840
+ }
841
+ }
842
+ },
843
+
844
+ // Performs the initial configuration of a View with a set of options.
845
+ // Keys with special meaning *(model, collection, id, className)*, are
846
+ // attached directly to the view.
847
+ _configure : function(options) {
848
+ if (this.options) options = _.extend({}, this.options, options);
849
+ if (options.model) this.model = options.model;
850
+ if (options.collection) this.collection = options.collection;
851
+ if (options.el) this.el = options.el;
852
+ if (options.id) this.id = options.id;
853
+ if (options.className) this.className = options.className;
854
+ if (options.tagName) this.tagName = options.tagName;
855
+ this.options = options;
856
+ },
857
+
858
+ // Ensure that the View has a DOM element to render into.
859
+ _ensureElement : function() {
860
+ if (this.el) return;
861
+ var attrs = {};
862
+ if (this.id) attrs.id = this.id;
863
+ if (this.className) attrs["class"] = this.className;
864
+ this.el = this.make(this.tagName, attrs);
865
+ }
866
+
867
+ });
868
+
869
+ // The self-propagating extend function that Backbone classes use.
870
+ var extend = function (protoProps, classProps) {
871
+ var child = inherits(this, protoProps, classProps);
872
+ child.extend = extend;
873
+ return child;
874
+ };
875
+
876
+ // Set up inheritance for the model, collection, and view.
877
+ Backbone.Model.extend = Backbone.Collection.extend =
878
+ Backbone.Controller.extend = Backbone.View.extend = extend;
879
+
880
+ // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
881
+ var methodMap = {
882
+ 'create': 'POST',
883
+ 'update': 'PUT',
884
+ 'delete': 'DELETE',
885
+ 'read' : 'GET'
886
+ };
887
+
888
+ // Backbone.sync
889
+ // -------------
890
+
891
+ // Override this function to change the manner in which Backbone persists
892
+ // models to the server. You will be passed the type of request, and the
893
+ // model in question. By default, uses makes a RESTful Ajax request
894
+ // to the model's `url()`. Some possible customizations could be:
895
+ //
896
+ // * Use `setTimeout` to batch rapid-fire updates into a single request.
897
+ // * Send up the models as XML instead of JSON.
898
+ // * Persist models via WebSockets instead of Ajax.
899
+ //
900
+ // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
901
+ // as `POST`, with a `_method` parameter containing the true HTTP method,
902
+ // as well as all requests with the body as `application/x-www-form-urlencoded` instead of
903
+ // `application/json` with the model in a param named `model`.
904
+ // Useful when interfacing with server-side languages like **PHP** that make
905
+ // it difficult to read the body of `PUT` requests.
906
+ Backbone.sync = function(method, model, success, error) {
907
+ var type = methodMap[method];
908
+ var modelJSON = (method === 'create' || method === 'update') ?
909
+ JSON.stringify(model.toJSON()) : null;
910
+
911
+ // Default JSON-request options.
912
+ var params = {
913
+ url: getUrl(model),
914
+ type: type,
915
+ contentType: 'application/json',
916
+ data: modelJSON,
917
+ dataType: 'json',
918
+ processData: false,
919
+ success: success,
920
+ error: error
921
+ };
922
+
923
+ // For older servers, emulate JSON by encoding the request into an HTML-form.
924
+ if (Backbone.emulateJSON) {
925
+ params.contentType = 'application/x-www-form-urlencoded';
926
+ params.processData = true;
927
+ params.data = modelJSON ? {model : modelJSON} : {};
928
+ }
929
+
930
+ // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
931
+ // And an `X-HTTP-Method-Override` header.
932
+ if (Backbone.emulateHTTP) {
933
+ if (type === 'PUT' || type === 'DELETE') {
934
+ if (Backbone.emulateJSON) params.data._method = type;
935
+ params.type = 'POST';
936
+ params.beforeSend = function(xhr) {
937
+ xhr.setRequestHeader("X-HTTP-Method-Override", type);
938
+ };
939
+ }
940
+ }
941
+
942
+ // Make the request.
943
+ $.ajax(params);
944
+ };
945
+
946
+ // Helpers
947
+ // -------
948
+
949
+ // Shared empty constructor function to aid in prototype-chain creation.
950
+ var ctor = function(){};
951
+
952
+ // Helper function to correctly set up the prototype chain, for subclasses.
953
+ // Similar to `goog.inherits`, but uses a hash of prototype properties and
954
+ // class properties to be extended.
955
+ var inherits = function(parent, protoProps, staticProps) {
956
+ var child;
957
+
958
+ // The constructor function for the new subclass is either defined by you
959
+ // (the "constructor" property in your `extend` definition), or defaulted
960
+ // by us to simply call `super()`.
961
+ if (protoProps && protoProps.hasOwnProperty('constructor')) {
962
+ child = protoProps.constructor;
963
+ } else {
964
+ child = function(){ return parent.apply(this, arguments); };
965
+ }
966
+
967
+ // Set the prototype chain to inherit from `parent`, without calling
968
+ // `parent`'s constructor function.
969
+ ctor.prototype = parent.prototype;
970
+ child.prototype = new ctor();
971
+
972
+ // Add prototype properties (instance properties) to the subclass,
973
+ // if supplied.
974
+ if (protoProps) _.extend(child.prototype, protoProps);
975
+
976
+ // Add static properties to the constructor function, if supplied.
977
+ if (staticProps) _.extend(child, staticProps);
978
+
979
+ // Correctly set child's `prototype.constructor`, for `instanceof`.
980
+ child.prototype.constructor = child;
981
+
982
+ // Set a convenience property in case the parent's prototype is needed later.
983
+ child.__super__ = parent.prototype;
984
+
985
+ return child;
986
+ };
987
+
988
+ // Helper function to get a URL from a Model or Collection as a property
989
+ // or as a function.
990
+ var getUrl = function(object) {
991
+ if (!(object && object.url)) throw new Error("A 'url' property or function must be specified");
992
+ return _.isFunction(object.url) ? object.url() : object.url;
993
+ };
994
+
995
+ // Wrap an optional error callback with a fallback error event.
996
+ var wrapError = function(onError, model, options) {
997
+ return function(resp) {
998
+ if (onError) {
999
+ onError(model, resp);
1000
+ } else {
1001
+ model.trigger('error', model, resp, options);
1002
+ }
1003
+ };
1004
+ };
1005
+
1006
+ // Helper function to escape a string for HTML rendering.
1007
+ var escapeHTML = function(string) {
1008
+ return string.replace(/&(?!\w+;)/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
1009
+ };
1010
+
1011
+ })();
1012
+