Browse Source

api service

Rafał Pitoń 9 years ago
parent
commit
e4be237b83

+ 4 - 4
misago/frontend/misago/routes/legal.js

@@ -22,14 +22,14 @@
             _.title.set(this.title);
           } else {
             _.title.set();
-            return _.api.one('legal-page', dashedTypeName);
+            return _.api.model('legal-page', dashedTypeName);
           }
         },
-        ondata: function(data, component, _) {
+        ondata: function(page, component, _) {
           m.startComputation();
 
-          data.title = data.title || defaultTitle;
-          this.page = _.models.deserialize('legal-page', data);
+          page.title = page.title || defaultTitle;
+          this.page = page;
           this.isReady = true;
 
           m.endComputation();

+ 10 - 10
misago/frontend/misago/services/ajax.js

@@ -1,17 +1,17 @@
 (function (Misago) {
   'use strict';
 
-  var Ajax = function(_) {
-    var getCsrfToken = function(cookie_name) {
-      if (document.cookie.indexOf(cookie_name) !== -1) {
-        var cookieRegex = new RegExp(cookie_name + '\=([^;]*)');
-        var cookie = Misago.get(document.cookie.match(cookieRegex), '');
-        return cookie.split('=')[1];
-      } else {
-        return null;
-      }
-    };
+  var getCsrfToken = function(cookie_name) {
+    if (document.cookie.indexOf(cookie_name) !== -1) {
+      var cookieRegex = new RegExp(cookie_name + '\=([^;]*)');
+      var cookie = Misago.get(document.cookie.match(cookieRegex), 0);
+      return cookie.split('=')[1];
+    } else {
+      return null;
+    }
+  };
 
+  var Ajax = function(_) {
     this.csrfToken = getCsrfToken(_.context.CSRF_COOKIE_NAME);
 
     /*

+ 100 - 13
misago/frontend/misago/services/api.js

@@ -1,30 +1,117 @@
 (function (Misago) {
   'use strict';
 
-  var Query = function(_, model) {
-
+  var filtersUrl = function(filters) {
+    if (typeof filters === 'object') {
+      var values = [];
+      for (var key in filters) {
+        if (filters.hasOwnProperty(key)) {
+          var encodedKey = encodeURIComponent(key);
+          var encodedValue = encodeURIComponent(filters[key]);
+          values.push(encodedKey + '=' + encodedValue);
+        }
+      }
+      return '?' + values.join('&');
+    } else {
+      return filters + '/';
+    }
   };
 
-  var Api = function(_) {
-    var apiRoot = _.setup.api;
+  var Query = function(_, call) {
+    this.url = call.url || _.setup.api;
+
+    if (call.path) {
+      this.url += call.path + '/';
+    } else if (call.related) {
+      this.url += call.related + '/';
+    } else {
+      this.url += call.model + 's' + '/';
+    }
+
+    if (call.filters) {
+      this.url += filtersUrl(call.filters);
+    }
 
-    this.buildUrl = function(model, call, querystrings) {
-      var url = _.setup.api;
-      url += 'api/' + model + '/';
-      return url;
+    if (!call.url && call.filters) {
+      if (call.model) {
+        this.related = function(model, filters) {
+          return new Query(_, {
+            url: this.url,
+            relation: call.model,
+            related: model,
+            filters: filters,
+          });
+        };
+      }
+
+      this.endpoint = function(path, filters) {
+        return new Query(_, {
+          url: this.url,
+          path: path,
+          filters: filters
+        });
+      };
+    }
+
+    this.get = function() {
+      var model = null;
+      if (call.related) {
+        model = call.relation + ':' + call.related;
+      } else if (call.model) {
+        model = call.model;
+      }
+
+      return _.ajax.get(this.url).then(function(data) {
+        if (model) {
+          if (data.results) {
+            data.results.map(function(item) {
+              return _.models.new(model, item);
+            });
+            return data;
+          } else {
+            return _.models.new(model, data);
+          }
+        } else {
+          return data;
+        }
+      });
     };
 
-    this.one = function(model, id) {
-      var url = this.buildUrl(model) + id + '/';
-      return _.ajax.get(url);
+    this.post = function(data) {
+      return _.ajax.post(this.url, data);
     };
 
-    this.many = function(model, filters) {
+    this.patch = function(data) {
+      return _.ajax.patch(this.url, data);
+    };
 
+    this.put = function(data) {
+      return _.ajax.put(this.url, data);
     };
 
-    this.call = function(model, target, call, data) {
+    this.delete = function() {
+      return _.ajax.delete(this.url);
+    };
+
+    // shortcut for get()
+    this.then = function(resolve, reject) {
+      return this.get().then(resolve, reject);
+    };
+  };
+
+  var Api = function(_) {
+    this.model = function(model, filters) {
+      return new Query(_, {
+        model: model,
+        filters: filters,
+      });
+    };
 
+    this.endpoint = function(path, filters) {
+      return new Query(_, {
+        path: path,
+        filters: filters
+      });
     };
   };
 

+ 13 - 0
misago/frontend/misago/services/models.js

@@ -4,6 +4,7 @@
   var Models = function() {
     this.classes = {};
     this.deserializers = {};
+    this.relations = {};
 
     this.add = function(name, kwargs) {
       if (kwargs.class) {
@@ -13,6 +14,14 @@
       if (kwargs.deserialize) {
         this.deserializers[name] = kwargs.deserialize;
       }
+
+      if (kwargs.relations) {
+        for (var key in kwargs.relations) {
+          if (kwargs.relations.hasOwnProperty(key)) {
+            this.relations[name + ':' + key] = kwargs.relations[key];
+          }
+        }
+      }
     };
 
     this.new = function(name, data) {
@@ -24,6 +33,10 @@
     };
 
     this.deserialize = function(name, json) {
+      if (this.relations[name]) {
+        name = this.relations[name];
+      }
+
       if (this.deserializers[name]) {
         return this.new(name, this.deserializers[name](json, this));
       } else {

+ 83 - 0
misago/frontend/test/tests/unit/api.js

@@ -0,0 +1,83 @@
+(function () {
+  'use strict';
+
+  var service = getMisagoService('api');
+  var container = {
+      setup: {
+        api: '/test-api/'
+      }
+    };
+
+  QUnit.module("API");
+
+  QUnit.test("service factory", function(assert) {
+    var api = service({});
+    assert.ok(api, "service factory has returned service instance.");
+  });
+
+  QUnit.test("model", function(assert) {
+    var api = service(container);
+
+    assert.equal(api.model('user', 'admin').url, '/test-api/users/admin/',
+      "model constructed valid url with string pk.");
+
+    assert.equal(api.model('user', 123).url, '/test-api/users/123/',
+      "model constructed valid url with integer pk.");
+
+    assert.equal(
+      api.model('user', {token: 'abc&df', uid: 123}).url,
+      '/test-api/users/?token=abc%26df&uid=123',
+      "model constructed valid url with querystring.");
+
+    assert.equal(api.model('user', 123).related('follows', 1).url,
+      '/test-api/users/123/follows/1/',
+      "model constructed valid related url.");
+
+    assert.equal(api.model('user', 123).endpoint('avatar').url,
+      '/test-api/users/123/avatar/',
+      "model constructed valid endpoint url.");
+
+    assert.ok(
+      !api.model('user', 123).endpoint('avatar').related,
+      "model can't have relation to endpoint.");
+
+    assert.ok(
+      !api.model('user', 123).related('avatar').related,
+      "model can't have relation to relation.");
+  });
+
+  QUnit.test("endpoint", function(assert) {
+    var api = service(container);
+
+    assert.equal(api.endpoint('auth').url, '/test-api/auth/',
+      "endpoint constructed valid url.");
+
+    assert.equal(
+      api.endpoint('auth', 'string-pk').url,
+      '/test-api/auth/string-pk/',
+      "endpoint constructed valid url with string pk.");
+
+    assert.equal(
+      api.endpoint('auth', 124).url,
+      '/test-api/auth/124/',
+      "endpoint constructed valid url with integer pk.");
+
+    assert.equal(
+      api.endpoint('auth', {token: 'abc&df', uid: 123}).url,
+      '/test-api/auth/?token=abc%26df&uid=123',
+      "endpoint constructed valid url with querystring.");
+
+    assert.ok(
+      !api.endpoint('auth', 124).related,
+      "endpoint can't have nested relation.");
+
+    assert.equal(
+      api.endpoint('auth', 124).endpoint('change-password').url,
+      '/test-api/auth/124/change-password/',
+      "nested endpoint constructed valid url with integer pk.");
+
+    assert.ok(
+      !api.endpoint('auth', 124).endpoint('change-password').endpoint,
+      "nested endpoint can't be nested further.");
+  });
+}());

+ 22 - 17
misago/frontend/test/tests/unit/models.js

@@ -1,12 +1,12 @@
-(function (Misago) {
+(function () {
   'use strict';
 
+  var service = getMisagoService('models');
+
   QUnit.module("Models");
 
   QUnit.test("service factory", function(assert) {
     var container = {};
-
-    var service = getMisagoService('models');
     var models = service(container);
 
     assert.ok(models,
@@ -15,15 +15,13 @@
 
   QUnit.test("add", function(assert) {
     var container = {};
-
-    var service = getMisagoService('models');
     var models = service(container);
 
     var TestModel = function(data) {
       this.name = data.name || 'Hello';
     };
 
-    var testModelDeserializer = function(data, models) {
+    var testModelDeserializer = function(data) {
       return data;
     };
 
@@ -33,15 +31,13 @@
     });
 
     assert.equal(models.classes['test-model'], TestModel,
-      "test model's class was registered in the service");
+      "test model's class was registered in the service.");
     assert.equal(models.deserializers['test-model'], testModelDeserializer,
-      "test model's deserializer was registered in the service");
+      "test model's deserializer was registered in the service.");
   });
 
   QUnit.test("new", function(assert) {
     var container = {};
-
-    var service = getMisagoService('models');
     var models = service(container);
 
     var TestModel = function(data) {
@@ -54,20 +50,18 @@
 
     var model = models.new('test-model', {name: 'Working!!!'});
     assert.equal(model.name, 'Working!!!',
-      "new() returned model instance");
+      "new() returned model instance.");
   });
 
   QUnit.test("deserialize", function(assert) {
     var container = {};
-
-    var service = getMisagoService('models');
     var models = service(container);
 
     var TestModel = function(data) {
       this.name = data.name;
     };
 
-    var testModelDeserializer = function(data, models) {
+    var testModelDeserializer = function(data) {
       data.name = data.title;
       return data;
     };
@@ -79,7 +73,7 @@
 
     var model = models.deserialize('test-model', {title: 'Testing!'});
     assert.equal(model.name, 'Testing!',
-      "deserialize() returned deserialized model instance");
+      "deserialize() returned deserialized model instance.");
 
     models.add('other-model', {
       class: TestModel
@@ -87,6 +81,17 @@
 
     model = models.deserialize('other-model', {name: 'Other!'});
     assert.equal(model.name, 'Other!',
-      "deserialize() returned model instance without deserialization");
+      "deserialize() returned model instance without deserialization.");
+
+    models.add('model-with-relation', {
+      class: TestModel,
+      relations: {
+        'test': 'test-model'
+      }
+    });
+
+    model = models.deserialize('model-with-relation:test', {title: 'Related'});
+    assert.equal(model.name, 'Related',
+      "deserialize() returned related model instance.");
   });
-}(Misago.prototype));
+}());

+ 2 - 3
misago/frontend/test/tests/unit/router.js

@@ -1,6 +1,8 @@
 (function () {
   'use strict';
 
+  var service = getMisagoService('router');
+
   QUnit.module("Router");
 
   QUnit.test("cleanUrl", function(assert) {
@@ -10,8 +12,6 @@
         'MEDIA_URL': 'http://nocookie.somewhere.com/'
       }
     };
-
-    var service = getMisagoService('router');
     var router = service(container);
 
     assert.equal(router.cleanUrl('/'), '/');
@@ -54,7 +54,6 @@
       }
     };
 
-    var service = getMisagoService('router');
     var router = service(container);
 
     assert.equal(router.staticUrl('logo.png'), '/static/logo.png',

+ 1 - 1
misago/static/misago/js/misago.js

@@ -1,2 +1,2 @@
-!function(){"use strict";window.Misago=function(){var t=Object.getPrototypeOf(this),e=this;this.context={SETTINGS:{}},this._initServices=function(r){var n=new t.OrderedList(r).order(!1);n.forEach(function(t){var r=null;r=void 0!==t.item.factory?t.item.factory:t.item;var n=r(e);n&&(e[t.key]=n)})},this._destroyServices=function(r){var n=new t.OrderedList(r).order();n.reverse(),n.forEach(function(t){void 0!==t.destroy&&t.destroy(e)})},this.setup=!1,this.init=function(e){this.setup={fixture:t.get(e,"fixture",null),inTest:t.get(e,"inTest",!1)},this._initServices(t._services)},this.destroy=function(){this._destroyServices(t._services)}};var t=window.Misago.prototype;t._services=[],t.addService=function(e,r,n){t._services.push({key:e,item:r,after:t.get(n,"after"),before:t.get(n,"before")})}}(),function(t){"use strict";t.has=function(t,e){return t?t.hasOwnProperty(e):!1},t.get=function(e,r,n){return t.has(e,r)?e[r]:void 0!==n?n:void 0},t.pop=function(e,r,n){var o=t.get(e,r,n);return t.has(e,r)&&delete e[r],o}}(Misago.prototype),function(t){"use strict";t.OrderedList=function(e){this.isOrdered=!1,this._items=e||[],this.add=function(e,r,n){this._items.push({key:e,item:r,after:t.get(n,"after"),before:t.get(n,"before")})},this.get=function(t,e){for(var r=0;r<this._items.length;r++)if(this._items[r].key===t)return this._items[r].item;return e},this.has=function(t){return void 0!==this.get(t)},this.values=function(){for(var t=[],e=0;e<this._items.length;e++)t.push(this._items[e].item);return t},this.order=function(t){return this.isOrdered||(this._items=this._order(this._items),this.isOrdered=!0),t||"undefined"==typeof t?this.values():this._items},this._order=function(t){function e(t){var e=-1;-1===o.indexOf(t.key)&&(t.after?(e=o.indexOf(t.after),-1!==e&&(e+=1)):t.before&&(e=o.indexOf(t.before)),-1!==e&&(n.splice(e,0,t),o.splice(e,0,t.key)))}var r=[];t.forEach(function(t){r.push(t.key)});var n=[],o=[];t.forEach(function(t){t.after||t.before||(n.push(t),o.push(t.key))}),t.forEach(function(t){"_end"===t.before&&(n.push(t),o.push(t.key))});for(var i=200;i>0&&r.length!==o.length;)i-=1,t.forEach(e);return n}}}(Misago.prototype),function(t){t.deserializeDatetime=function(t){return t?moment(t):null},t.serializeDatetime=function(t){return t?t.format():null}}(Misago.prototype),function(t){"use strict";t.startsWith=function(t,e){return 0===t.indexOf(e)},t.endsWith=function(t,e){return-1!==t.indexOf(e,t.length-e.length)}}(Misago.prototype),function(t){"use strict";t.UrlConfInvalidComponentError=function(t){this.message="route's "+t+" component should be an array or object",this.toString=function(){return this.message}},t.UrlConf=function(){var e=this;this._patterns=[],this.patterns=function(){return this._patterns};var r=function(t,e){return(t+e).replace("//","/")},n=function(t,n){for(var o=0;o<n.length;o++)e.url(r(t,n[o].pattern),n[o].component,n[o].name)};this.url=function(e,r,o){if("object"!=typeof r)throw new t.UrlConfInvalidComponentError(o);""===e&&(e="/"),r instanceof t.UrlConf?n(e,r.patterns()):this._patterns.push({pattern:e,component:r,name:o})}}}(Misago.prototype),function(t){"use strict";t.loadingPage=function(e){return m(".page.page-loading",e.component(t.Loader))}}(Misago.prototype),function(t){"use strict";var e=function(e){var r=new RegExp(e.context.CSRF_COOKIE_NAME+"=([^;]*)");this.csrfToken=t.get(document.cookie.match(r),0).split("=")[1];var n={};this.ajax=function(e,r,o,i){var s=m.deferred(),a={url:r,method:e,headers:{"X-CSRFToken":this.csrfToken},data:o|{},dataType:"json",success:function(o){"GET"===e&&t.pop(n,r),s.resolve(o)},error:function(o){"GET"===e&&t.pop(n,r);var i=o.responseJSON||{};i.status=o.status,i.statusText=o.statusText,s.reject(i)}};return i?void 0:($.ajax(a),s.promise)},this.get=function(r){var o=t.pop(e.context,r);if(o){var i=m.deferred();return i.resolve(o),i.promise}return void 0!==n[r]?n[r]:(n[r]=this.ajax("GET",r),n[r])},this.post=function(t){return this.ajax("POST",t)}};t.addService("ajax",function(t){return new e(t)})}(Misago.prototype),function(t){"use strict";var e=function(t){this.buildUrl=function(e,r,n){var o=t.router.baseUrl;return o+="api/"+e+"/"},this.one=function(e,r){var n=this.buildUrl(e)+r+"/";return t.ajax.get(n)},this.many=function(t,e){},this.call=function(t,e,r,n){}};t.addService("api",function(t){return new e(t)})}(Misago.prototype),function(t){"use strict";t.addService("component-factory",function(t){t.component=function(){for(var e=[],r=0;r<arguments.length;r+=1)e.push(arguments[r]);return e.push(t),m.component.apply(void 0,e)}})}(Misago.prototype),function(t){"use strict";t.addService("conf",function(e){e.settings=t.get(e.context,"SETTINGS",{})})}(Misago.prototype),function(t){"use strict";t.addService("forum-layout",{factory:function(e){e.setup.fixture&&m.mount(document.getElementById(e.setup.fixture),e.component(t.ForumLayout))},destroy:function(t){t.setup.fixture&&m.mount(t.setup.fixture,null)}},{before:"start-routing"})}(Misago.prototype),function(t){"use strict";t.addService("set-momentjs-locale",function(){moment.locale($("html").attr("lang"))})}(Misago.prototype),function(t){"use strict";var e=function(){};t.route=function(r){r.isActive=!0;var n=r.controller||e;if(r.controller=function(){r.isActive=!0;var t=n.apply(r,arguments)||{},o=t.onunload||e;return t.onunload=function(){o.apply(r,arguments),r.isActive=!1},t},r.vm&&r.vm.init){var o=r.vm.init;r.vm.init=function(){var t=arguments,e=o.apply(r.vm,t);e&&e.then(function(){if(r.isActive&&r.vm.ondata){for(var e=[],n=0;n<arguments.length;n++)e.push(arguments[n]);for(var o=0;o<t.length;o++)e.push(t[o]);r.vm.ondata.apply(r.vm,e)}},function(t){r.isActive&&r.container.router.errorPage(t)})},r.loading||(r.loading=function(){var e=this.container;return m(".page.page-loading",e.component(t.Loader))});var i=r.view;r.view=function(){return r.vm.isReady?i.apply(r,arguments):r.loading.apply(r,arguments)}}return r}}(Misago.prototype),function(t){"use strict";var e=function(e){var r=this;this.baseUrl=$("base").attr("href");var n=t.get(e.context,"STATIC_URL","/"),o=t.get(e.context,"MEDIA_URL","/");this.urls={},this.reverses={};var i=function(t){return t.container=e,t},s=function(t){t.patterns().forEach(function(t){var e=r.baseUrl+t.pattern;e=e.replace("//","/"),r.urls[e]=i(t.component),r.reverses[t.name]=e})};this.startRouting=function(t,e){s(t),this.fixture=e,m.route.mode="pathname",m.route(e,"/",this.urls)},this.url=function(t){return this.reverses[t]},this.delegateElement=null,this.delegateName="click.misago-router",this.cleanUrl=function(t){if(t){var e="/"===t.substr(0,1)&&"//"!==t.substr(0,2);if(!e){var r=window.location;if("//"!==t.substr(0,2)){var i=t.substr(0,r.protocol.length+2);if(i!==r.protocol+"//")return;t=t.substr(r.protocol.length+2)}else t=t.substr(2);if(t.substr(0,r.host.length)!==r.host)return;t=t.substr(r.host.length)}if(t.substr(0,this.baseUrl.length)===this.baseUrl&&t.substr(0,n.length)!==n&&t.substr(0,o.length)!==o){var s="/user-avatar/";if(t.substr(0,s.length)!==s)return t}}},this.delegateClicks=function(t){this.delegateElement=t,$(this.delegateElement).on(this.delegateName,"a",function(t){var e=r.cleanUrl(t.target.href);e&&(e!=m.route()&&m.route(e),t.preventDefault())})},this.destroy=function(){$(this.delegateElement).off(this.delegateName)};var a=function(t){return function(e){return t+e}};this.staticUrl=a(n),this.mediaUrl=a(o),this.error403=function(e){var r=null;e.ban?(r=i(t.ErrorBannedRoute),r.error={message:e.detail,ban:t.Ban.deserialize(e.ban)}):(r=i(t.Error403Route),r.error=e.detail),m.mount(this.fixture,r)},this.error404=function(){m.mount(this.fixture,i(t.Error404Route))},this.error500=function(){m.mount(this.fixture,i(t.Error500Route))},this.error0=function(){m.mount(this.fixture,i(t.Error0Route))},this.errorPage=function(t){0===t.status&&this.error0(),500===t.status&&this.error500(),404===t.status&&this.error404(),403===t.status&&this.error403(t)}};t.addService("router",function(t){return new e(t)}),t.addService("start-routing",function(e){e.router.startRouting(t.urls,document.getElementById("router-fixture")),e.router.delegateClicks(document.getElementById(e.setup.fixture))},{before:"_end"})}(Misago.prototype),function(t){"use strict";var e=function(t){var e=this;this._intervals={},this.run=function(r,n,o){this._intervals[n]=window.setTimeout(function(){var i=r(t);i!==!1&&e.run(r,n,o)},o)},this.runOnce=function(e,r,n){this._intervals[r]=window.setTimeout(function(){e(t)},n)},this.stop=function(){for(var t in this._intervals)this._intervals.hasOwnProperty(t)&&(window.clearTimeout(this._intervals[t]),delete this._intervals[t])}};t.addService("runloop",{factory:function(t){return new e(t)},destroy:function(t){t.runloop.stop()}})}(Misago.prototype),function(t){"use strict";t.addService("start-tick",function(t){t.runloop.run(function(){m.startComputation(),m.endComputation()},"tick",6e4)})}(Misago.prototype),function(t){"use strict";t.addService("page-title",function(t){t._setTitle=function(t){"string"==typeof t&&(t={title:t});var e=t.title;"undefined"!=typeof t.page&&t.page>1&&(e+=" ("+interpolate(gettext("page %(page)s"),{page:t.page},!0)+")"),"undefined"!=typeof t.parent&&(e+=" | "+t.parent),document.title=e+" | "+this.settings.forum_name},t.setTitle=function(t){t?this._setTitle(t):document.title=this.settings.forum_name}})}(Misago.prototype),function(t){"use strict";t.Ban=function(t){this.message={html:t.message.html,plain:t.message.plain},this.expires_on=t.expires_on},t.Ban.deserialize=function(e){return e.expires_on=t.deserializeDatetime(e.expires_on),new t.Ban(e)}}(Misago.prototype),function(t){"use strict";var e=function(t){var e=[m("p.lead",t.message)];return t.help&&e.push(m("p.help",t.help)),m(".page.error-page.error-"+t.code+"-page",m(".container",m(".error-panel",[m(".error-icon",m("span.material-icon",t.icon)),m(".error-message",e)])))};t.ErrorBannedRoute=t.route({controller:function(){this.container.setTitle(gettext("You are banned"))},error:null,view:function(){var t=[];t.push(this.error.ban.message.html?m(".lead",m.trust(this.error.ban.message.html)):m("p.lead",this.error.message));var e=null;return e=this.error.ban.expires_on?this.error.ban.expires_on.isAfter(moment())?interpolate(gettext("This ban expires %(expires_on)s."),{expires_on:this.error.ban.expires_on.fromNow()},!0):gettext("This ban has expired."):gettext("This ban is permanent."),t.push(m("p",e)),m(".page.error-page.error-banned-page",m(".container",m(".error-panel",[m(".error-icon",m("span.material-icon","highlight_off")),m(".error-message",t)])))}}),t.Error403Route=t.route({controller:function(){this.container.setTitle(gettext("Page not available"))},error:null,view:function(){return e({code:403,icon:"remove_circle_outline",message:gettext("This page is not available."),help:this.error||gettext("You don't have permission to access this page.")})}}),t.Error404Route=t.route({controller:function(){this.container.setTitle(gettext("Page not found"))},view:function(){return e({code:404,icon:"info_outline",message:gettext("Requested page could not be found."),help:gettext("The link you followed was incorrect or the page has been moved or deleted.")})}}),t.Error500Route=t.route({controller:function(){this.container.setTitle(gettext("Application error occured"))},view:function(){return e({code:500,icon:"error_outline",message:gettext("Requested page could not be displayed due to an error."),help:gettext("Please try again later or contact site staff if error persists.")})}}),t.Error0Route=t.route({controller:function(){this.container.setTitle(gettext("Lost connection with application"))},view:function(){return e({code:500,icon:"sync_problem",message:gettext("Could not connect to application."),help:gettext("This may be caused by problems with your connection or application server. Please check your internet connection and refresh page if problem persists.")})}})}(Misago.prototype),function(t){"use strict";t.IndexRoute=t.route({controller:function(){var t=this.container;document.title=t.settings.forum_index_title||t.settings.forum_name;var e=m.prop(0);return{count:e,increment:function(){console.log("increment()"),e(e()+1)}}},view:function(t){return m(".container",[m("h1",["Count: ",m("strong",t.count())]),m("p","Clicky click button to increase count!."),m("p",m("button.btn.btn-primary",{onclick:t.increment},"Clicky clicky!"))])}})}(Misago.prototype),function(t){"use strict";var e=function(e,r){var n=e.replace(/_/g,"-");return t.route({controller:function(){var r=this.container;t.get(r.settings,e+"_link")?window.location=t.get(r.settings,e+"_link"):this.vm.init(this,r)},vm:{isReady:!1,init:function(t,e){return this.isReady?void e.setTitle(this.title):(e.setTitle(),e.api.one("legal-pages",n))},ondata:function(t,e,n){m.startComputation(),this.title=t.title||r,this.body=t.body,this.isReady=!0,m.endComputation(),e.isActive&&n.setTitle(t.title)}},view:function(){var e=this.container;return m(".page.legal-page."+n+"-page",[e.component(t.PageHeader,{title:this.vm.title}),m(".container",m.trust(this.vm.body))])}})};t.TermsOfServiceRoute=e("terms_of_service",gettext("Terms of service")),t.PrivacyPolicyRoute=e("privacy_policy",gettext("Privacy policy"))}(Misago.prototype),function(t){"use strict";var e=function(e,r,n){var o=t.get(e.settings,r+"_link");return!o&&t.get(e.settings,r)&&(o=e.router.url(r)),o?m("li",m("a",{href:o},t.get(e.settings,r+"_title",n))):null};t.FooterNav={isVisible:function(t){return-1!==[!!t.forum_footnote,!!t.terms_of_service,!!t.terms_of_service_link,!!t.privacy_policy,!!t.privacy_policy_link].indexOf(!0)},view:function(t,r){var n=[];return r.settings.forum_footnote&&n.push(m("li.forum-footnote",m.trust(r.settings.forum_footnote))),n.push(e(r,"terms_of_service",gettext("Terms of service"))),n.push(e(r,"privacy_policy",gettext("Privacy policy"))),m("ul.list-inline.footer-nav",n)}}}(Misago.prototype),function(t){"use strict";t.ForumFooter={view:function(e,r){var n=null;return t.FooterNav.isVisible(r.settings)&&(n=r.component(t.FooterNav)),m("footer.forum-footer",[m(".container",m(".footer-content",[n,r.component(t.FooterMisagoBranding)]))])}}}(Misago.prototype),function(t){"use strict";t.FooterMisagoBranding={view:function(){return m("a.misago-branding[href=http://misago-project.org]",["powered by ",m("strong","misago")])}}}(Misago.prototype),function(t){"use strict";t.BrandFull={view:function(t,e,r){var n=[m("img",{src:r.router.staticUrl("misago/img/site-logo.png"),alt:r.settings.forum_name})];return e&&n.push(e),m("a.navbar-brand",{href:r.router.url("index")},n)}}}(Misago.prototype),function(t){"use strict";t.ForumNavbar={view:function(e,r){var n=[];return r.settings.forum_branding_display&&n.push(r.component(t.BrandFull,r.settings.forum_branding_text)),n.push(m("ul.nav.navbar-nav",[m("li",m("a",{config:m.route,href:r.router.url("index")},"Index"))])),m('nav.navbar.navbar-default.navbar-static-top[role="navigation"]',[m(".container.navbar-full.hidden-xs.hidden-sm",n)])}}}(Misago.prototype),function(t){"use strict";var e=function(t,e,r){r.retain=!0};t.ForumLayout={view:function(r,n){return[n.component(t.ForumNavbar),m("#router-fixture",{config:e}),n.component(t.ForumFooter)]}}}(Misago.prototype),function(t){"use strict";t.Loader={view:function(){return m(".loader.sk-folding-cube",[m(".sk-cube1.sk-cube"),m(".sk-cube2.sk-cube"),m(".sk-cube4.sk-cube"),m(".sk-cube3.sk-cube")])}},t.LoadingPage={view:function(e,r){return m(".page.loading-page",r.component(t.Loader))}}}(Misago.prototype),function(t){"use strict";var e=function(t,e,r){r.retain=!0};t.MisagoMarkup={view:function(t,r){return m("article.misago-markup",{config:e},m.trust(r))}}}(Misago.prototype),function(t){"use strict";t.PageHeader={view:function(t,e){return m(".page-header",m(".container",[m("h1",e.title)]))}}}(Misago.prototype),function(t,e){"use strict";var r=new e;r.url("/",t.IndexRoute,"index"),r.url("/terms-of-service/",t.TermsOfServiceRoute,"terms_of_service"),r.url("/privacy-policy/",t.PrivacyPolicyRoute,"privacy_policy"),t.urls=r}(Misago.prototype,Misago.prototype.UrlConf);
+!function(){"use strict";window.Misago=function(){var t=Object.getPrototypeOf(this),e=this;this.context={SETTINGS:{}},this._initServices=function(r){var n=new t.OrderedList(r).order(!1);n.forEach(function(t){var r=null;r=void 0!==t.item.factory?t.item.factory:t.item;var n=r(e);n&&(e[t.key]=n)})},this._destroyServices=function(r){var n=new t.OrderedList(r).order();n.reverse(),n.forEach(function(t){void 0!==t.destroy&&t.destroy(e)})},this.setup=!1,this.init=function(e){this.setup={fixture:t.get(e,"fixture",null),inTest:t.get(e,"inTest",!1),api:t.get(e,"api","/api/")},this._initServices(t._services)},this.destroy=function(){this._destroyServices(t._services)}};var t=window.Misago.prototype;t._services=[],t.addService=function(e,r,n){t._services.push({key:e,item:r,after:t.get(n,"after"),before:t.get(n,"before")})}}(),function(t){"use strict";t.has=function(t,e){return t?t.hasOwnProperty(e):!1},t.get=function(e,r,n){return t.has(e,r)?e[r]:void 0!==n?n:void 0},t.pop=function(e,r,n){var i=t.get(e,r,n);return t.has(e,r)&&(e[r]=null),i}}(Misago.prototype),function(t){"use strict";t.OrderedList=function(e){this.isOrdered=!1,this._items=e||[],this.add=function(e,r,n){this._items.push({key:e,item:r,after:t.get(n,"after"),before:t.get(n,"before")})},this.get=function(t,e){for(var r=0;r<this._items.length;r++)if(this._items[r].key===t)return this._items[r].item;return e},this.has=function(t){return void 0!==this.get(t)},this.values=function(){for(var t=[],e=0;e<this._items.length;e++)t.push(this._items[e].item);return t},this.order=function(t){return this.isOrdered||(this._items=this._order(this._items),this.isOrdered=!0),t||"undefined"==typeof t?this.values():this._items},this._order=function(t){function e(t){var e=-1;-1===i.indexOf(t.key)&&(t.after?(e=i.indexOf(t.after),-1!==e&&(e+=1)):t.before&&(e=i.indexOf(t.before)),-1!==e&&(n.splice(e,0,t),i.splice(e,0,t.key)))}var r=[];t.forEach(function(t){r.push(t.key)});var n=[],i=[];t.forEach(function(t){t.after||t.before||(n.push(t),i.push(t.key))}),t.forEach(function(t){"_end"===t.before&&(n.push(t),i.push(t.key))});for(var o=200;o>0&&r.length!==i.length;)o-=1,t.forEach(e);return n}}}(Misago.prototype),function(t){t.serializeDatetime=function(t){return t?t.format():null},t.deserializeDatetime=function(t){return t?moment(t):null}}(Misago.prototype),function(t){"use strict";t.startsWith=function(t,e){return 0===t.indexOf(e)},t.endsWith=function(t,e){return-1!==t.indexOf(e,t.length-e.length)}}(Misago.prototype),function(t){"use strict";t.UrlConfInvalidComponentError=function(t){this.message="route's "+t+" component should be an array or object",this.toString=function(){return this.message}},t.UrlConf=function(){var e=this;this._patterns=[],this.patterns=function(){return this._patterns};var r=function(t,e){return(t+e).replace("//","/")},n=function(t,n){for(var i=0;i<n.length;i++)e.url(r(t,n[i].pattern),n[i].component,n[i].name)};this.url=function(e,r,i){if("object"!=typeof r)throw new t.UrlConfInvalidComponentError(i);""===e&&(e="/"),r instanceof t.UrlConf?n(e,r.patterns()):this._patterns.push({pattern:e,component:r,name:i})}}}(Misago.prototype),function(t){"use strict";t.loadingPage=function(e){return m(".page.page-loading",e.component(t.Loader))}}(Misago.prototype),function(t){"use strict";var e=function(e){if(-1!==document.cookie.indexOf(e)){var r=new RegExp(e+"=([^;]*)"),n=t.get(document.cookie.match(r),0);return n.split("=")[1]}return null},r=function(r){this.csrfToken=e(r.context.CSRF_COOKIE_NAME);var n={};this.ajax=function(e,r,i,o){var s=m.deferred(),a={url:r,method:e,headers:{"X-CSRFToken":this.csrfToken},data:i|{},dataType:"json",success:function(i){"GET"===e&&t.pop(n,r),s.resolve(i)},error:function(i){"GET"===e&&t.pop(n,r);var o=i.responseJSON||{};o.status=i.status,o.statusText=i.statusText,s.reject(o)}};return o?void 0:($.ajax(a),s.promise)},this.get=function(e){var i=t.pop(r.context,e);if(i){var o=m.deferred();return o.resolve(i),o.promise}return void 0!==n[e]?n[e]:(n[e]=this.ajax("GET",e),n[e])},this.post=function(t,e){return this.ajax("POST",t,e)},this.patch=function(t,e){return this.ajax("PATCH",t,e)},this.put=function(t,e){return this.ajax("PUT",t,e)},this["delete"]=function(t){return this.ajax("DELETE",t)}};t.addService("ajax",function(t){return new r(t)})}(Misago.prototype),function(t){"use strict";var e=function(t){if("object"==typeof t){var e=[];for(var r in t)if(t.hasOwnProperty(r)){var n=encodeURIComponent(r),i=encodeURIComponent(t[r]);e.push(n+"="+i)}return"?"+e.join("&")}return t+"/"},r=function(t,n){this.url=n.url||t.setup.api,this.url+=n.path?n.path+"/":n.related?n.related+"/":n.model+"s/",n.filters&&(this.url+=e(n.filters)),!n.url&&n.filters&&(n.model&&(this.related=function(e,i){return new r(t,{url:this.url,relation:n.model,related:e,filters:i})}),this.endpoint=function(e,n){return new r(t,{url:this.url,path:e,filters:n})}),this.get=function(){var e=null;return n.related?e=n.relation+":"+n.related:n.model&&(e=n.model),t.ajax.get(this.url).then(function(r){return e?r.results?(r.results.map(function(r){return t.models["new"](e,r)}),r):t.models["new"](e,r):r})},this.post=function(e){return t.ajax.post(this.url,e)},this.patch=function(e){return t.ajax.patch(this.url,e)},this.put=function(e){return t.ajax.put(this.url,e)},this["delete"]=function(){return t.ajax["delete"](this.url)},this.then=function(t,e){return this.get().then(t,e)}},n=function(t){this.model=function(e,n){return new r(t,{model:e,filters:n})},this.endpoint=function(e,n){return new r(t,{path:e,filters:n})}};t.addService("api",function(t){return new n(t)})}(Misago.prototype),function(t){"use strict";t.addService("component-factory",function(t){t.component=function(){for(var e=[],r=0;r<arguments.length;r+=1)e.push(arguments[r]);return e.push(t),m.component.apply(void 0,e)}})}(Misago.prototype),function(t){"use strict";t.addService("conf",function(e){e.settings=t.get(e.context,"SETTINGS",{})})}(Misago.prototype),function(t){"use strict";t.addService("forum-layout",{factory:function(e){e.setup.fixture&&m.mount(document.getElementById(e.setup.fixture),e.component(t.ForumLayout))},destroy:function(t){t.setup.fixture&&m.mount(t.setup.fixture,null)}},{before:"start-routing"})}(Misago.prototype),function(t){"use strict";var e=function(){this.classes={},this.deserializers={},this.relations={},this.add=function(t,e){if(e["class"]&&(this.classes[t]=e["class"]),e.deserialize&&(this.deserializers[t]=e.deserialize),e.relations)for(var r in e.relations)e.relations.hasOwnProperty(r)&&(this.relations[t+":"+r]=e.relations[r])},this["new"]=function(t,e){return this.classes[t]?new this.classes[t](e):e},this.deserialize=function(t,e){return this.relations[t]&&(t=this.relations[t]),this.deserializers[t]?this["new"](t,this.deserializers[t](e,this)):this["new"](t,e)}};t.addService("models",function(){return new e})}(Misago.prototype),function(t){"use strict";t.addService("set-momentjs-locale",function(){moment.locale($("html").attr("lang"))})}(Misago.prototype),function(t){"use strict";var e=function(){};t.route=function(r){r.isActive=!0;var n=r.controller||e;if(r.controller=function(){r.isActive=!0;var t=n.apply(r,arguments)||{},i=t.onunload||e;return t.onunload=function(){i.apply(r,arguments),r.isActive=!1},t},r.vm&&r.vm.init){var i=r.vm.init;r.vm.init=function(){var t=arguments,e=i.apply(r.vm,t);e&&e.then(function(){if(r.isActive&&r.vm.ondata){for(var e=[],n=0;n<arguments.length;n++)e.push(arguments[n]);for(var i=0;i<t.length;i++)e.push(t[i]);r.vm.ondata.apply(r.vm,e)}},function(t){r.isActive&&r.container.router.errorPage(t)})},r.loading||(r.loading=function(){var e=this.container;return m(".page.page-loading",e.component(t.Loader))});var o=r.view;r.view=function(){return r.vm.isReady?o.apply(r,arguments):r.loading.apply(r,arguments)}}return r}}(Misago.prototype),function(t){"use strict";var e=function(e){var r=this;this.baseUrl=$("base").attr("href");var n=t.get(e.context,"STATIC_URL","/"),i=t.get(e.context,"MEDIA_URL","/");this.urls={},this.reverses={};var o=function(t){return t.container=e,t},s=function(t){t.patterns().forEach(function(t){var e=r.baseUrl+t.pattern;e=e.replace("//","/"),r.urls[e]=o(t.component),r.reverses[t.name]=e})};this.startRouting=function(t,e){s(t),this.fixture=e,m.route.mode="pathname",m.route(e,"/",this.urls)},this.url=function(t){return this.reverses[t]},this.delegateElement=null,this.delegateName="click.misago-router",this.cleanUrl=function(t){if(t){var e="/"===t.substr(0,1)&&"//"!==t.substr(0,2);if(!e){var r=window.location;if("//"!==t.substr(0,2)){var o=t.substr(0,r.protocol.length+2);if(o!==r.protocol+"//")return;t=t.substr(r.protocol.length+2)}else t=t.substr(2);if(t.substr(0,r.host.length)!==r.host)return;t=t.substr(r.host.length)}if(t.substr(0,this.baseUrl.length)===this.baseUrl&&t.substr(0,n.length)!==n&&t.substr(0,i.length)!==i){var s="/user-avatar/";if(t.substr(0,s.length)!==s)return t}}},this.delegateClicks=function(t){this.delegateElement=t,$(this.delegateElement).on(this.delegateName,"a",function(t){var e=r.cleanUrl(t.target.href);e&&(e!=m.route()&&m.route(e),t.preventDefault())})},this.destroy=function(){$(this.delegateElement).off(this.delegateName)};var a=function(t){return function(e){return t+e}};this.staticUrl=a(n),this.mediaUrl=a(i),this.error403=function(r){var n=null;r.ban?(n=o(t.ErrorBannedRoute),n.error={message:r.detail,ban:e.models.deserialize("ban",r.ban)}):(n=o(t.Error403Route),n.error=r.detail),m.mount(this.fixture,n)},this.error404=function(){m.mount(this.fixture,o(t.Error404Route))},this.error500=function(){m.mount(this.fixture,o(t.Error500Route))},this.error0=function(){m.mount(this.fixture,o(t.Error0Route))},this.errorPage=function(t){0===t.status&&this.error0(),500===t.status&&this.error500(),404===t.status&&this.error404(),403===t.status&&this.error403(t)}};t.addService("router",function(t){return new e(t)}),t.addService("start-routing",function(e){e.router.startRouting(t.urls,document.getElementById("router-fixture")),e.router.delegateClicks(document.getElementById(e.setup.fixture))},{before:"_end"})}(Misago.prototype),function(t){"use strict";var e=function(t){var e=this;this._intervals={};var r=function(t){e._intervals[t]&&(window.clearTimeout(e._intervals[t]),e._intervals[t]=null)};this.run=function(n,i,o){this._intervals[i]=window.setTimeout(function(){r(i);var s=n(t);s!==!1&&e.run(n,i,o)},o)},this.runOnce=function(e,n,i){this._intervals[n]=window.setTimeout(function(){r(n),e(t)},i)},this.stop=function(t){for(var e in this._intervals)t&&t!==e||r(e)}};t.addService("runloop",{factory:function(t){return new e(t)},destroy:function(t){t.runloop.stop()}})}(Misago.prototype),function(t){"use strict";t.addService("start-tick",function(t){var e=m.prop();t.runloop.run(function(){m.startComputation(),e(e()+1),m.endComputation()},"tick",6e4)})}(Misago.prototype),function(t){"use strict";var e=function(t){this.set=function(e){e?this._set_complex(e):document.title=t},this._set_complex=function(e){"string"==typeof e&&(e={title:e});var r=e.title;if("undefined"!=typeof e.page&&e.page>1){var n=interpolate(gettext("page %(page)s"),{page:e.page},!0);r+=" ("+n+")"}"undefined"!=typeof e.parent&&(r+=" | "+e.parent),document.title=r+" | "+t}};t.addService("page-title",function(t){t.title=new e(t.settings.forum_name)})}(Misago.prototype),function(t){"use strict";var e=function(t){this.message={html:t.message.html,plain:t.message.plain},this.expires_on=t.expires_on},r=function(e){return e.expires_on=t.deserializeDatetime(e.expires_on),new t.Ban(e)};t.addService("ban-model",function(t){t.models.add("ban",{"class":e,deserialize:r})},{after:"models"})}(Misago.prototype),function(t){"use strict";var e=function(t){this.title=t.title,this.body=t.body};t.addService("legal-page-model",function(t){t.models.add("legal-page",{"class":e})},{after:"models"})}(Misago.prototype),function(t){"use strict";var e=function(t){var e=[m("p.lead",t.message)];return t.help&&e.push(m("p.help",t.help)),m(".page.error-page.error-"+t.code+"-page",m(".container",m(".error-panel",[m(".error-icon",m("span.material-icon",t.icon)),m(".error-message",e)])))};t.ErrorBannedRoute=t.route({controller:function(){this.container.title.set(gettext("You are banned"))},error:null,view:function(){var t=[];t.push(this.error.ban.message.html?m(".lead",m.trust(this.error.ban.message.html)):m("p.lead",this.error.message));var e=null;return e=this.error.ban.expires_on?this.error.ban.expires_on.isAfter(moment())?interpolate(gettext("This ban expires %(expires_on)s."),{expires_on:this.error.ban.expires_on.fromNow()},!0):gettext("This ban has expired."):gettext("This ban is permanent."),t.push(m("p",e)),m(".page.error-page.error-banned-page",m(".container",m(".error-panel",[m(".error-icon",m("span.material-icon","highlight_off")),m(".error-message",t)])))}}),t.Error403Route=t.route({controller:function(){this.container.title.set(gettext("Page not available"))},error:null,view:function(){return e({code:403,icon:"remove_circle_outline",message:gettext("This page is not available."),help:this.error||gettext("You don't have permission to access this page.")})}}),t.Error404Route=t.route({controller:function(){this.container.title.set(gettext("Page not found"))},view:function(){return e({code:404,icon:"info_outline",message:gettext("Requested page could not be found."),help:gettext("The link you followed was incorrect or the page has been moved or deleted.")})}}),t.Error500Route=t.route({controller:function(){this.container.title.set(gettext("Application error occured"))},view:function(){return e({code:500,icon:"error_outline",message:gettext("Requested page could not be displayed due to an error."),help:gettext("Please try again later or contact site staff if error persists.")})}}),t.Error0Route=t.route({controller:function(){this.container.title.set(gettext("Lost connection with application"))},view:function(){return e({code:500,icon:"sync_problem",message:gettext("Could not connect to application."),help:gettext("This may be caused by problems with your connection or application server. Please check your internet connection and refresh page if problem persists.")})}})}(Misago.prototype),function(t){"use strict";t.IndexRoute=t.route({controller:function(){var t=this.container;document.title=t.settings.forum_index_title||t.settings.forum_name;var e=m.prop(0);return{count:e,increment:function(){console.log("increment()"),e(e()+1)}}},view:function(t){return m(".container",[m("h1",["Count: ",m("strong",t.count())]),m("p","Clicky click button to increase count!."),m("p",m("button.btn.btn-primary",{onclick:t.increment},"Clicky clicky!"))])}})}(Misago.prototype),function(t){"use strict";var e=function(e,r){var n=e.replace(/_/g,"-");return t.route({controller:function(){var r=this.container;t.get(r.settings,e+"_link")?window.location=t.get(r.settings,e+"_link"):this.vm.init(this,r)},vm:{page:null,isReady:!1,init:function(t,e){return this.isReady?void e.title.set(this.title):(e.title.set(),e.api.model("legal-page",n))},ondata:function(t,e,n){m.startComputation(),t.title=t.title||r,this.page=t,this.isReady=!0,m.endComputation(),e.isActive&&n.title.set(this.page.title)}},view:function(){var e=this.container;return m(".page.legal-page."+n+"-page",[e.component(t.PageHeader,{title:this.vm.page.title}),m(".container",e.component(t.Markup,this.vm.page.body))])}})};t.TermsOfServiceRoute=e("terms_of_service",gettext("Terms of service")),t.PrivacyPolicyRoute=e("privacy_policy",gettext("Privacy policy"))}(Misago.prototype),function(t){"use strict";var e=function(e,r,n){var i=t.get(e.settings,r+"_link");return!i&&t.get(e.settings,r)&&(i=e.router.url(r)),i?m("li",m("a",{href:i},t.get(e.settings,r+"_title",n))):null};t.FooterNav={isVisible:function(t){return-1!==[!!t.forum_footnote,!!t.terms_of_service,!!t.terms_of_service_link,!!t.privacy_policy,!!t.privacy_policy_link].indexOf(!0)},view:function(t,r){var n=[];return r.settings.forum_footnote&&n.push(m("li.forum-footnote",m.trust(r.settings.forum_footnote))),n.push(e(r,"terms_of_service",gettext("Terms of service"))),n.push(e(r,"privacy_policy",gettext("Privacy policy"))),m("ul.list-inline.footer-nav",n)}}}(Misago.prototype),function(t){"use strict";t.ForumFooter={view:function(e,r){var n=null;return t.FooterNav.isVisible(r.settings)&&(n=r.component(t.FooterNav)),m("footer.forum-footer",[m(".container",m(".footer-content",[n,r.component(t.FooterMisagoBranding)]))])}}}(Misago.prototype),function(t){"use strict";t.FooterMisagoBranding={view:function(){return m("a.misago-branding[href=http://misago-project.org]",["powered by ",m("strong","misago")])}}}(Misago.prototype),function(t){"use strict";t.BrandFull={view:function(t,e,r){var n=[m("img",{src:r.router.staticUrl("misago/img/site-logo.png"),alt:r.settings.forum_name})];return e&&n.push(e),m("a.navbar-brand",{href:r.router.url("index")},n)}}}(Misago.prototype),function(t){"use strict";t.ForumNavbar={view:function(e,r){var n=[];r.settings.forum_branding_display&&n.push(r.component(t.BrandFull,r.settings.forum_branding_text)),n.push(m("ul.nav.navbar-nav",[m("li",m("a",{config:m.route,href:r.router.url("index")},"Index"))]));var i=".navbar.navbar-default.navbar-static-top";return m("nav"+i+'[role="navigation"]',[m(".container.navbar-full.hidden-xs.hidden-sm",n)])}}}(Misago.prototype),function(t){"use strict";var e=function(t,e,r){r.retain=!0};t.ForumLayout={view:function(r,n){return[n.component(t.ForumNavbar),m("#router-fixture",{config:e}),n.component(t.ForumFooter)]}}}(Misago.prototype),function(t){"use strict";t.Loader={view:function(){return m(".loader.sk-folding-cube",[m(".sk-cube1.sk-cube"),m(".sk-cube2.sk-cube"),m(".sk-cube4.sk-cube"),m(".sk-cube3.sk-cube")])}},t.LoadingPage={view:function(e,r){return m(".page.loading-page",r.component(t.Loader))}}}(Misago.prototype),function(t){"use strict";var e=function(t,e,r){r.retain=!0};t.Markup={view:function(t,r){return m("article.misago-markup",{config:e},m.trust(r))}}}(Misago.prototype),function(t){"use strict";t.PageHeader={view:function(t,e){return m(".page-header",m(".container",[m("h1",e.title)]))}}}(Misago.prototype),function(t,e){"use strict";var r=new e;r.url("/",t.IndexRoute,"index"),r.url("/terms-of-service/",t.TermsOfServiceRoute,"terms_of_service"),r.url("/privacy-policy/",t.PrivacyPolicyRoute,"privacy_policy"),t.urls=r}(Misago.prototype,Misago.prototype.UrlConf);
 //# sourceMappingURL=/misago.js.map

+ 1 - 1
misago/static/misago/js/misago.js.map

@@ -1 +1 @@
-{"version":3,"sources":["misago.js"],"names":["window","Misago","ns","Object","getPrototypeOf","this","self","context","SETTINGS","_initServices","services","orderedServices","OrderedList","order","forEach","item","factory","undefined","serviceInstance","key","_destroyServices","reverse","destroy","setup","init","fixture","get","inTest","_services","proto","prototype","addService","name","push","after","before","has","obj","hasOwnProperty","value","pop","returnValue","items","isOrdered","_items","add","i","length","values","values_only","_order","unordered","insertItem","insertAt","ordering","indexOf","ordered","splice","index","iterations","deserializeDatetime","deserialized","moment","serializeDatetime","serialized","format","startsWith","string","beginning","endsWith","tail","UrlConfInvalidComponentError","message","toString","UrlConf","_patterns","patterns","prefixPattern","prefix","pattern","replace","include","url","component","loadingPage","_","m","Loader","Ajax","cookieRegex","RegExp","CSRF_COOKIE_NAME","csrfToken","document","cookie","match","split","runningGets","ajax","method","data","progress","promise","deferred","ajax_settings","headers","X-CSRFToken","dataType","success","resolve","error","jqXHR","rejection","responseJSON","status","statusText","reject","$","preloaded","post","Api","buildUrl","model","call","querystrings","router","baseUrl","one","id","many","filters","target","argumentsArray","arguments","apply","settings","mount","getElementById","ForumLayout","locale","attr","noop","route","isActive","__controller","controller","__onunload","onunload","vm","__init","initArgs","then","ondata","finalArgs","f","container","errorPage","loading","__view","view","isReady","Router","staticUrl","mediaUrl","urls","reverses","routedComponent","populatePatterns","urlconf","finalPattern","startRouting","mode","delegateElement","delegateName","cleanUrl","isRelative","substr","location","protocol","host","avatarsUrl","delegateClicks","element","on","e","href","preventDefault","off","prefixUrl","error403","ban","ErrorBannedRoute","detail","Ban","deserialize","Error403Route","error404","Error404Route","error500","Error500Route","error0","Error0Route","RunLoop","_intervals","run","callable","delay","setTimeout","result","runOnce","stop","clearTimeout","runloop","startComputation","endComputation","_setTitle","title","completeTitle","page","interpolate","gettext","parent","forum_name","setTitle","html","plain","expires_on","error_message","help","code","icon","trust","expirationMessage","isAfter","fromNow","IndexRoute","forum_index_title","count","prop","increment","console","log","ctrl","onclick","legalPageFactory","typeName","defaultTitle","dashedTypeName","api","body","PageHeader","TermsOfServiceRoute","PrivacyPolicyRoute","legalLink","legalType","FooterNav","isVisible","forum_footnote","terms_of_service","terms_of_service_link","privacy_policy","privacy_policy_link","ForumFooter","nav","FooterMisagoBranding","BrandFull","branding","children","src","alt","ForumNavbar","desktopNavbar","forum_branding_display","forum_branding_text","config","persistent","el","isInit","retain","LoadingPage","setupMarkup","MisagoMarkup","content","options"],"mappings":"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","file":"misago.js","sourcesContent":["/* global -Misago */\n/* exported Misago */\n(function () {\n  'use strict';\n\n  window.Misago = function() {\n    var ns = Object.getPrototypeOf(this);\n    var self = this;\n\n    // Context data\n    this.context = {\n      // Empty settings\n      SETTINGS: {}\n    };\n\n    // Services init/destroy\n    this._initServices = function(services) {\n      var orderedServices = new ns.OrderedList(services).order(false);\n      orderedServices.forEach(function (item) {\n        var factory = null;\n        if (item.item.factory !== undefined) {\n          factory = item.item.factory;\n        } else {\n          factory = item.item;\n        }\n\n        var serviceInstance = factory(self);\n        if (serviceInstance) {\n          self[item.key] = serviceInstance;\n        }\n      });\n    };\n\n    this._destroyServices = function(services) {\n      var orderedServices = new ns.OrderedList(services).order();\n      orderedServices.reverse();\n      orderedServices.forEach(function (item) {\n        if (item.destroy !== undefined) {\n          item.destroy(self);\n        }\n      });\n    };\n\n    // App init/destory\n    this.setup = false;\n    this.init = function(setup) {\n      this.setup = {\n        fixture: ns.get(setup, 'fixture', null),\n        inTest: ns.get(setup, 'inTest', false)\n      };\n\n      this._initServices(ns._services);\n    };\n\n    this.destroy = function() {\n      this._destroyServices(ns._services);\n    };\n  };\n\n\n  // Services registry\n  var proto = window.Misago.prototype;\n  proto._services = [];\n\n  proto.addService = function(name, factory, order) {\n    proto._services.push({\n      key: name,\n      item: factory,\n      after: proto.get(order, 'after'),\n      before: proto.get(order, 'before')\n    });\n  };\n}());\n\n(function (Misago) {\n  'use strict';\n\n  Misago.has = function(obj, key) {\n    if (obj) {\n      return obj.hasOwnProperty(key);\n    } else {\n      return false;\n    }\n  };\n\n  Misago.get = function(obj, key, value) {\n    if (Misago.has(obj, key)) {\n      return obj[key];\n    } else if (value !== undefined) {\n      return value;\n    } else {\n      return undefined;\n    }\n  };\n\n  Misago.pop = function(obj, key, value) {\n    var returnValue = Misago.get(obj, key, value);\n    if (Misago.has(obj, key)) {\n      delete obj[key];\n    }\n    return returnValue;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.OrderedList = function(items) {\n    this.isOrdered = false;\n    this._items = items || [];\n\n    this.add = function(key, item, order) {\n      this._items.push({\n        key: key,\n        item: item,\n        after: Misago.get(order, 'after'),\n        before: Misago.get(order, 'before')\n      });\n    };\n\n    this.get = function(key, value) {\n      for (var i = 0; i < this._items.length; i++) {\n        if (this._items[i].key === key) {\n          return this._items[i].item;\n        }\n      }\n\n      return value;\n    };\n\n    this.has = function(key) {\n      return this.get(key) !== undefined;\n    };\n\n    this.values = function() {\n      var values = [];\n      for (var i = 0; i < this._items.length; i++) {\n        values.push(this._items[i].item);\n      }\n      return values;\n    };\n\n    this.order = function(values_only) {\n      if (!this.isOrdered) {\n        this._items = this._order(this._items);\n        this.isOrdered = true;\n      }\n\n      if (values_only || typeof values_only === 'undefined') {\n        return this.values();\n      } else {\n        return this._items;\n      }\n    };\n\n    this._order = function(unordered) {\n      // Index of unordered items\n      var index = [];\n      unordered.forEach(function (item) {\n        index.push(item.key);\n      });\n\n      // Ordered items\n      var ordered = [];\n      var ordering = [];\n\n      // First pass: register items that\n      // don't specify their order\n      unordered.forEach(function (item) {\n        if (!item.after && !item.before) {\n          ordered.push(item);\n          ordering.push(item.key);\n        }\n      });\n\n      // Second pass: register items that\n      // specify their before to \"_end\"\n      unordered.forEach(function (item) {\n        if (item.before === \"_end\") {\n          ordered.push(item);\n          ordering.push(item.key);\n        }\n      });\n\n      // Third pass: keep iterating items\n      // until we hit iterations limit or finish\n      // ordering list\n      function insertItem(item) {\n        var insertAt = -1;\n        if (ordering.indexOf(item.key) === -1) {\n          if (item.after) {\n            insertAt = ordering.indexOf(item.after);\n            if (insertAt !== -1) {\n              insertAt += 1;\n            }\n          } else if (item.before) {\n            insertAt = ordering.indexOf(item.before);\n          }\n\n          if (insertAt !== -1) {\n            ordered.splice(insertAt, 0, item);\n            ordering.splice(insertAt, 0, item.key);\n          }\n        }\n      }\n\n      var iterations = 200;\n      while (iterations > 0 && index.length !== ordering.length) {\n        iterations -= 1;\n        unordered.forEach(insertItem);\n      }\n\n      return ordered;\n    };\n  };\n} (Misago.prototype));\n\n(function (Misago) {\n  Misago.deserializeDatetime = function(deserialized) {\n    return deserialized ? moment(deserialized) : null;\n  };\n\n  Misago.serializeDatetime = function(serialized) {\n    return serialized ? serialized.format() : null;\n  };\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.startsWith = function(string, beginning) {\n    return string.indexOf(beginning) === 0;\n  };\n\n  Misago.endsWith = function(string, tail) {\n    return string.indexOf(tail, string.length - tail.length) !== -1;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.UrlConfInvalidComponentError = function(name) {\n    this.message = \"route's \" + name + \" component should be an array or object\";\n\n    this.toString = function() {\n      return this.message;\n    };\n  };\n\n  Misago.UrlConf = function() {\n    var self = this;\n    this._patterns = [];\n\n    this.patterns = function() {\n      return this._patterns;\n    };\n\n    var prefixPattern = function(prefix, pattern) {\n      return (prefix + pattern).replace('//', '/');\n    };\n\n    var include = function(prefix, patterns) {\n      for (var i = 0; i < patterns.length; i ++) {\n        self.url(prefixPattern(prefix, patterns[i].pattern),\n                 patterns[i].component,\n                 patterns[i].name);\n      }\n    };\n\n    this.url = function(pattern, component, name) {\n      if (typeof component !== 'object') {\n        throw new Misago.UrlConfInvalidComponentError(name);\n      }\n\n      if (pattern === '') {\n        pattern = '/';\n      }\n\n      if (component instanceof Misago.UrlConf) {\n        include(pattern, component.patterns());\n      } else {\n        this._patterns.push({\n          pattern: pattern,\n          component: component,\n          name: name\n        });\n      }\n    };\n  };\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.loadingPage = function(_) {\n    return m('.page.page-loading', _.component(Misago.Loader));\n  };\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Ajax = function(_) {\n    var cookieRegex = new RegExp(_.context.CSRF_COOKIE_NAME + '\\=([^;]*)');\n    this.csrfToken = Misago.get(document.cookie.match(cookieRegex), 0).split('=')[1];\n\n    /*\n      List of GETs underway\n      We are limiting number of GETs to API to 1 per url\n    */\n    var runningGets = {};\n\n    this.ajax = function(method, url, data, progress) {\n      var promise = m.deferred();\n\n      var ajax_settings = {\n        url: url,\n        method: method,\n        headers: {\n          'X-CSRFToken': this.csrfToken\n        },\n\n        data: data | {},\n        dataType: 'json',\n\n        success: function(data) {\n          if (method === 'GET') {\n            Misago.pop(runningGets, url);\n          }\n          promise.resolve(data);\n        },\n        error: function(jqXHR) {\n          if (method === 'GET') {\n            Misago.pop(runningGets, url);\n          }\n\n          var rejection = jqXHR.responseJSON || {};\n\n          rejection.status = jqXHR.status;\n          rejection.statusText = jqXHR.statusText;\n\n          promise.reject(rejection);\n        }\n      };\n\n      if (progress) {\n        return; // not implemented... yet!\n      }\n\n      $.ajax(ajax_settings);\n      return promise.promise;\n    };\n\n    this.get = function(url) {\n      var preloaded = Misago.pop(_.context, url);\n      if (preloaded) {\n        var deferred = m.deferred();\n        deferred.resolve(preloaded);\n        return deferred.promise;\n      } else if (runningGets[url] !== undefined) {\n        return runningGets[url];\n      } else {\n        runningGets[url] = this.ajax('GET', url);\n        return runningGets[url];\n      }\n    };\n\n    this.post = function(url) {\n      return this.ajax('POST', url);\n    };\n  };\n\n  Misago.addService('ajax', function(_) {\n    return new Ajax(_);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Api = function(_) {\n    this.buildUrl = function(model, call, querystrings) {\n      var url = _.router.baseUrl;\n      url += 'api/' + model + '/';\n      return url;\n    };\n\n    this.one = function(model, id) {\n      var url = this.buildUrl(model) + id + '/';\n      return _.ajax.get(url);\n    };\n\n    this.many = function(model, filters) {\n\n    };\n\n    this.call = function(model, target, call, data) {\n\n    };\n  };\n\n  Misago.addService('api', function(_) {\n    return new Api(_);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('component-factory', function(_) {\n    // Component factory\n    _.component = function() {\n      var argumentsArray = [];\n      for (var i = 0; i < arguments.length; i += 1) {\n        argumentsArray.push(arguments[i]);\n      }\n\n      argumentsArray.push(_);\n      return m.component.apply(undefined, argumentsArray);\n    };\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('conf', function(_) {\n    _.settings = Misago.get(_.context, 'SETTINGS', {});\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('forum-layout', {\n    factory: function(_) {\n      if (_.setup.fixture) {\n        m.mount(document.getElementById(_.setup.fixture),\n                _.component(Misago.ForumLayout));\n      }\n    },\n\n    destroy: function(_) {\n      if (_.setup.fixture) {\n        m.mount(_.setup.fixture, null);\n      }\n    }\n  }, {before: 'start-routing'});\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('set-momentjs-locale', function() {\n    moment.locale($('html').attr('lang'));\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var noop = function() {};\n\n  Misago.route = function(component) {\n    /*\n      Boilerplate for Misago top-level components\n    */\n\n    // Component state\n    component.isActive = true;\n\n    // Wrap controller to store lifecycle methods\n    var __controller = component.controller || noop;\n    component.controller = function() {\n      component.isActive = true;\n\n      var controller = __controller.apply(component, arguments) || {};\n\n      // wrap onunload for lifestate\n      var __onunload = controller.onunload || noop;\n      controller.onunload = function() {\n        __onunload.apply(component, arguments);\n        component.isActive = false;\n      };\n\n      return controller;\n    };\n\n    // Add state callbacks to View-Model\n    if (component.vm && component.vm.init) {\n      // wrap vm.init in promise handler\n      var __init = component.vm.init;\n      component.vm.init = function() {\n        var initArgs = arguments;\n        var promise = __init.apply(component.vm, initArgs);\n\n        if (promise) {\n          promise.then(function() {\n            if (component.isActive && component.vm.ondata) {\n              var finalArgs = [];\n              for (var i = 0; i < arguments.length; i++) {\n                finalArgs.push(arguments[i]);\n              }\n              for (var f = 0; f < initArgs.length; f++) {\n                finalArgs.push(initArgs[f]);\n              }\n\n              component.vm.ondata.apply(component.vm, finalArgs);\n            }\n          }, function(error) {\n            if (component.isActive) {\n              component.container.router.errorPage(error);\n            }\n          });\n        }\n      };\n\n      // setup default loading view\n      if (!component.loading) {\n        component.loading = function () {\n          var _ = this.container;\n          return m('.page.page-loading',\n            _.component(Misago.Loader)\n          );\n        };\n      }\n\n      var __view = component.view;\n      component.view = function() {\n        if (component.vm.isReady) {\n          return __view.apply(component, arguments);\n        } else {\n          return component.loading.apply(component, arguments);\n        }\n      };\n    }\n\n    return component;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Router = function(_) {\n    var self = this;\n    this.baseUrl = $('base').attr('href');\n\n    var staticUrl = Misago.get(_.context, 'STATIC_URL', '/');\n    var mediaUrl = Misago.get(_.context, 'MEDIA_URL', '/');\n\n    // Routing\n    this.urls = {};\n    this.reverses = {};\n\n    var routedComponent = function(component) {\n      component.container = _;\n      return component;\n    };\n\n    var populatePatterns = function(urlconf) {\n      urlconf.patterns().forEach(function(url) {\n        // set service container on component\n\n        var finalPattern = self.baseUrl + url.pattern;\n        finalPattern = finalPattern.replace('//', '/');\n\n        self.urls[finalPattern] = routedComponent(url.component);\n        self.reverses[url.name] = finalPattern;\n      });\n    };\n\n    this.startRouting = function(urlconf, fixture) {\n      populatePatterns(urlconf);\n      this.fixture = fixture;\n\n      m.route.mode = 'pathname';\n      m.route(fixture, '/', this.urls);\n    };\n\n    this.url = function(name) {\n      return this.reverses[name];\n    };\n\n    // Delegate clicks\n    this.delegateElement = null;\n    this.delegateName = 'click.misago-router';\n\n    this.cleanUrl = function(url) {\n      if (!url) { return; }\n\n      // Is link relative?\n      var isRelative = url.substr(0, 1) === '/' && url.substr(0, 2) !== '//';\n\n      // If link contains host, validate to see if its outgoing\n      if (!isRelative) {\n        var location = window.location;\n\n        // If protocol matches current one, strip it from string\n        // otherwhise stop handler\n        if (url.substr(0, 2) !== '//') {\n          var protocol = url.substr(0, location.protocol.length + 2);\n          if (protocol !== location.protocol + '//') { return; }\n          url = url.substr(location.protocol.length + 2);\n        } else {\n          url = url.substr(2);\n        }\n\n        // Host checks out?\n        if (url.substr(0, location.host.length) !== location.host) { return; }\n        url = url.substr(location.host.length);\n      }\n\n      // Is link within Ember app?\n      if (url.substr(0, this.baseUrl.length) !== this.baseUrl) { return; }\n\n      // Is link to media/static/avatar server?\n      if (url.substr(0, staticUrl.length) === staticUrl) { return; }\n\n      if (url.substr(0, mediaUrl.length) === mediaUrl) { return; }\n\n      var avatarsUrl = '/user-avatar/';\n      if (url.substr(0, avatarsUrl.length) === avatarsUrl) { return; }\n\n      return url;\n    };\n\n    this.delegateClicks = function(element) {\n      this.delegateElement = element;\n      $(this.delegateElement).on(this.delegateName, 'a', function(e) {\n        var cleanUrl = self.cleanUrl(e.target.href);\n        if (cleanUrl) {\n          if (cleanUrl != m.route()) {\n            m.route(cleanUrl);\n          }\n          e.preventDefault();\n        }\n      });\n    };\n\n    this.destroy = function() {\n      $(this.delegateElement).off(this.delegateName);\n    };\n\n    // Media/Static url\n    var prefixUrl = function(prefix) {\n      return function(url) {\n        return prefix + url;\n      };\n    };\n\n    this.staticUrl = prefixUrl(staticUrl);\n    this.mediaUrl = prefixUrl(mediaUrl);\n\n    // Errors\n    this.error403 = function(error) {\n      var component = null;\n      if (error.ban) {\n        component = routedComponent(Misago.ErrorBannedRoute);\n        component.error = {\n          message: error.detail,\n          ban: Misago.Ban.deserialize(error.ban)\n        };\n      } else {\n        component = routedComponent(Misago.Error403Route);\n        component.error = error.detail;\n      }\n\n      m.mount(this.fixture, component);\n    };\n\n    this.error404 = function() {\n      m.mount(this.fixture, routedComponent(Misago.Error404Route));\n    };\n\n    this.error500 = function() {\n      m.mount(this.fixture, routedComponent(Misago.Error500Route));\n    };\n\n    this.error0 = function() {\n      m.mount(this.fixture, routedComponent(Misago.Error0Route));\n    };\n\n    this.errorPage = function(error) {\n      if (error.status === 0) {\n        this.error0();\n      }\n\n      if (error.status === 500) {\n        this.error500();\n      }\n\n      if (error.status === 404) {\n        this.error404();\n      }\n\n      if (error.status === 403) {\n        this.error403(error);\n      }\n    };\n  };\n\n  Misago.addService('router', function(_) {\n    return new Router(_);\n  });\n\n  Misago.addService('start-routing', function(_) {\n    _.router.startRouting(Misago.urls, document.getElementById('router-fixture'));\n    _.router.delegateClicks(document.getElementById(_.setup.fixture));\n  }, {before: '_end'});\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var RunLoop = function(_) {\n    var self = this;\n\n    this._intervals = {};\n\n    this.run = function(callable, name, delay) {\n      this._intervals[name] = window.setTimeout(function() {\n        var result = callable(_);\n        if (result !== false) {\n          self.run(callable, name, delay);\n        }\n      }, delay);\n    };\n\n    this.runOnce = function(callable, name, delay) {\n      this._intervals[name] = window.setTimeout(function() {\n        callable(_);\n      }, delay);\n    };\n\n    this.stop = function() {\n      for (var name in this._intervals) {\n        if (this._intervals.hasOwnProperty(name)) {\n          window.clearTimeout(this._intervals[name]);\n          delete this._intervals[name];\n        }\n      }\n    };\n  };\n\n  Misago.addService('runloop', {\n    factory: function(_) {\n      return new RunLoop(_);\n    },\n\n    destroy: function(_) {\n      _.runloop.stop();\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('start-tick', function(_) {\n    _.runloop.run(function() {\n      m.startComputation();\n      // just tick once a minute so stuff gets rerendered\n      // syncing dynamic timestamps, etc ect\n      m.endComputation();\n    }, 'tick', 60000);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('page-title', function(_) {\n    _._setTitle = function(title) {\n      if (typeof title === 'string') {\n        title = {title: title};\n      }\n\n      var completeTitle = title.title;\n\n      if (typeof title.page !== 'undefined' && title.page > 1) {\n        completeTitle += ' (' + interpolate(gettext('page %(page)s'), { page:title.page }, true) + ')';\n      }\n\n      if (typeof title.parent !== 'undefined') {\n        completeTitle += ' | ' + title.parent;\n      }\n\n      document.title = completeTitle + ' | ' + this.settings.forum_name;\n    };\n\n    _.setTitle = function(title) {\n      if (title) {\n        this._setTitle(title);\n      } else {\n        document.title = this.settings.forum_name;\n      }\n    };\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.Ban = function(data) {\n    this.message = {\n      html: data.message.html,\n      plain: data.message.plain,\n    };\n\n    this.expires_on = data.expires_on;\n  };\n\n  Misago.Ban.deserialize = function(data) {\n    data.expires_on = Misago.deserializeDatetime(data.expires_on);\n\n    return new Misago.Ban(data);\n  };\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var errorPage = function(error) {\n    var error_message = [\n      m('p.lead', error.message)\n    ];\n\n    if (error.help) {\n      error_message.push(m('p.help', error.help));\n    }\n\n    return m('.page.error-page.error-' + error.code + '-page',\n      m('.container',\n        m('.error-panel', [\n          m('.error-icon',\n            m('span.material-icon', error.icon)\n          ),\n          m('.error-message', error_message)\n        ])\n      )\n    );\n  };\n\n  Misago.ErrorBannedRoute = Misago.route({\n    controller: function() {\n      this.container.setTitle(gettext('You are banned'));\n    },\n    error: null,\n    view: function() {\n      var error_message = [];\n      if (this.error.ban.message.html) {\n        error_message.push(m('.lead', m.trust(this.error.ban.message.html)));\n      } else {\n        error_message.push(m('p.lead', this.error.message));\n      }\n\n      var expirationMessage = null;\n      if (this.error.ban.expires_on) {\n        if (this.error.ban.expires_on.isAfter(moment())) {\n          expirationMessage = interpolate(\n            gettext('This ban expires %(expires_on)s.'),\n            { 'expires_on': this.error.ban.expires_on.fromNow() },\n            true);\n        } else {\n          expirationMessage = gettext('This ban has expired.');\n        }\n      } else {\n        expirationMessage = gettext('This ban is permanent.');\n      }\n      error_message.push(m('p', expirationMessage));\n\n      return m('.page.error-page.error-banned-page',\n        m('.container',\n          m('.error-panel', [\n            m('.error-icon',\n              m('span.material-icon', 'highlight_off')\n            ),\n            m('.error-message', error_message)\n          ])\n        )\n      );\n    }\n  });\n\n  Misago.Error403Route = Misago.route({\n    controller: function() {\n      this.container.setTitle(gettext('Page not available'));\n    },\n    error: null,\n    view: function() {\n      return errorPage({\n        code: 403,\n        icon: 'remove_circle_outline',\n        message: gettext(\"This page is not available.\"),\n        help: this.error || gettext(\"You don't have permission to access this page.\")\n      });\n    }\n  });\n\n  Misago.Error404Route = Misago.route({\n    controller: function() {\n      this.container.setTitle(gettext('Page not found'));\n    },\n    view: function() {\n      return errorPage({\n        code: 404,\n        icon: 'info_outline',\n        message: gettext(\"Requested page could not be found.\"),\n        help: gettext(\"The link you followed was incorrect or the page has been moved or deleted.\")\n      });\n    }\n  });\n\n  Misago.Error500Route = Misago.route({\n    controller: function() {\n      this.container.setTitle(gettext('Application error occured'));\n    },\n    view: function() {\n      return errorPage({\n        code: 500,\n        icon: 'error_outline',\n        message: gettext(\"Requested page could not be displayed due to an error.\"),\n        help: gettext(\"Please try again later or contact site staff if error persists.\")\n      });\n    }\n  });\n\n  Misago.Error0Route = Misago.route({\n    controller: function() {\n      this.container.setTitle(gettext('Lost connection with application'));\n    },\n    view: function() {\n      return errorPage({\n        code: 500,\n        icon: 'sync_problem',\n        message: gettext(\"Could not connect to application.\"),\n        help: gettext(\"This may be caused by problems with your connection or application server. Please check your internet connection and refresh page if problem persists.\")\n      });\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.IndexRoute = Misago.route({\n    controller: function() {\n      var _ = this.container;\n      document.title = _.settings.forum_index_title || _.settings.forum_name;\n\n      var count = m.prop(0);\n\n      return {\n        count: count,\n        increment: function() {\n          console.log('increment()');\n          count(count() + 1);\n        }\n      };\n    },\n    view: function(ctrl) {\n      return m('.container', [\n        m('h1', ['Count: ', m('strong', ctrl.count())]),\n        m('p', 'Clicky click button to increase count!.'),\n        m('p',\n          m('button.btn.btn-primary', {onclick: ctrl.increment}, 'Clicky clicky!')\n        )\n      ]);\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var legalPageFactory = function(typeName, defaultTitle) {\n    var dashedTypeName = typeName.replace(/_/g, '-');\n\n    return Misago.route({\n      controller: function() {\n        var _ = this.container;\n\n        if (Misago.get(_.settings, typeName + '_link')) {\n          window.location = Misago.get(_.settings, typeName + '_link');\n        } else {\n          this.vm.init(this, _);\n        }\n      },\n      vm: {\n        isReady: false,\n        init: function(component, _) {\n          if (this.isReady) {\n            _.setTitle(this.title);\n          } else {\n            _.setTitle();\n            return _.api.one('legal-pages', dashedTypeName);\n          }\n        },\n        ondata: function(data, component, _) {\n          m.startComputation();\n\n          this.title = data.title || defaultTitle;\n          this.body = data.body;\n          this.isReady = true;\n\n          m.endComputation();\n\n          if (component.isActive) {\n            _.setTitle(data.title);\n          }\n        }\n      },\n      view: function() {\n        var _ = this.container;\n\n        return m('.page.legal-page.' + dashedTypeName + '-page', [\n          _.component(Misago.PageHeader, {title: this.vm.title}),\n          m('.container',\n            m.trust(this.vm.body)\n          )\n        ]);\n      }\n    });\n  };\n\n  Misago.TermsOfServiceRoute = legalPageFactory(\n    'terms_of_service', gettext('Terms of service'));\n  Misago.PrivacyPolicyRoute = legalPageFactory(\n    'privacy_policy', gettext('Privacy policy'));\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var legalLink = function(_, legalType, defaultTitle) {\n    var url = Misago.get(_.settings, legalType + '_link');\n    if (!url && Misago.get(_.settings, legalType)) {\n      url = _.router.url(legalType);\n    }\n\n    if (url) {\n      return m('li',\n        m('a', {href: url}, Misago.get(_.settings, legalType + '_title', defaultTitle))\n      );\n    } else {\n      return null;\n    }\n  };\n\n  Misago.FooterNav = {\n    isVisible: function(settings) {\n      return [\n        !!settings.forum_footnote,\n        !!settings.terms_of_service,\n        !!settings.terms_of_service_link,\n        !!settings.privacy_policy,\n        !!settings.privacy_policy_link\n      ].indexOf(true) !== -1;\n    },\n    view: function(ctrl, _) {\n      var items = [];\n\n      if (_.settings.forum_footnote) {\n        items.push(m('li.forum-footnote', m.trust(_.settings.forum_footnote)));\n      }\n\n      items.push(legalLink(_, 'terms_of_service', gettext('Terms of service')));\n      items.push(legalLink(_, 'privacy_policy', gettext('Privacy policy')));\n\n      return m('ul.list-inline.footer-nav', items);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.ForumFooter = {\n    view: function(ctrl, _) {\n      var nav = null;\n      if (Misago.FooterNav.isVisible(_.settings)) {\n        nav = _.component(Misago.FooterNav);\n      }\n\n      return m('footer.forum-footer', [\n        m('.container',\n          m('.footer-content', [\n            nav,\n            _.component(Misago.FooterMisagoBranding)\n          ])\n        )\n      ]);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.FooterMisagoBranding = {\n    view: function() {\n      return m('a.misago-branding[href=http://misago-project.org]', [\n        \"powered by \", m('strong', \"misago\")\n      ]);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.BrandFull = {\n    view: function(ctrl, branding, _) {\n      var children = [\n        m('img', {\n          src: _.router.staticUrl('misago/img/site-logo.png'),\n          alt: _.settings.forum_name\n        })\n      ];\n\n      if (branding) {\n        children.push(branding);\n      }\n\n      return m('a.navbar-brand', {href: _.router.url('index')}, children);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.ForumNavbar = {\n    view: function(ctrl, _) {\n      var desktopNavbar = [];\n\n      if (_.settings.forum_branding_display) {\n        desktopNavbar.push(_.component(Misago.BrandFull, _.settings.forum_branding_text));\n      }\n\n      desktopNavbar.push(m('ul.nav.navbar-nav', [\n        m('li', m(\"a\", {config: m.route, href: _.router.url('index')}, 'Index'))\n      ]));\n\n      return m('nav.navbar.navbar-default.navbar-static-top[role=\"navigation\"]', [\n        m('.container.navbar-full.hidden-xs.hidden-sm', desktopNavbar)\n      ]);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var persistent = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  Misago.ForumLayout = {\n    view: function(ctrl, _) {\n      return [\n        _.component(Misago.ForumNavbar),\n        m('#router-fixture', {config: persistent}),\n        _.component(Misago.ForumFooter)\n      ];\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.Loader = {\n    view: function() {\n      return m('.loader.sk-folding-cube', [\n        m('.sk-cube1.sk-cube'),\n        m('.sk-cube2.sk-cube'),\n        m('.sk-cube4.sk-cube'),\n        m('.sk-cube3.sk-cube')\n      ]);\n    }\n  };\n\n  Misago.LoadingPage = {\n    view: function(ctrl, _) {\n      return m('.page.loading-page',\n        _.component(Misago.Loader)\n      );\n    }\n  };\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var setupMarkup = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  Misago.MisagoMarkup = {\n    view: function(ctrl, content) {\n      return m('article.misago-markup', {config: setupMarkup}, m.trust(content));\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.PageHeader = {\n    view: function(ctrl, options) {\n      return m('.page-header',\n        m('.container', [\n          m('h1', options.title),\n        ])\n      );\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago, UrlConf) {\n  'use strict';\n\n  var urls = new UrlConf();\n  urls.url('/', Misago.IndexRoute, 'index');\n\n  // Legal pages\n  urls.url('/terms-of-service/', Misago.TermsOfServiceRoute, 'terms_of_service');\n  urls.url('/privacy-policy/', Misago.PrivacyPolicyRoute, 'privacy_policy');\n\n  Misago.urls = urls;\n} (Misago.prototype, Misago.prototype.UrlConf));\n"],"sourceRoot":"/source/"}
+{"version":3,"sources":["misago.js"],"names":["window","Misago","ns","Object","getPrototypeOf","this","self","context","SETTINGS","_initServices","services","orderedServices","OrderedList","order","forEach","item","factory","undefined","serviceInstance","key","_destroyServices","reverse","destroy","setup","init","fixture","get","inTest","api","_services","proto","prototype","addService","name","push","after","before","has","obj","hasOwnProperty","value","pop","returnValue","items","isOrdered","_items","add","i","length","values","values_only","_order","unordered","insertItem","insertAt","ordering","indexOf","ordered","splice","index","iterations","serializeDatetime","serialized","format","deserializeDatetime","deserialized","moment","startsWith","string","beginning","endsWith","tail","UrlConfInvalidComponentError","message","toString","UrlConf","_patterns","patterns","prefixPattern","prefix","pattern","replace","include","url","component","loadingPage","_","m","Loader","getCsrfToken","cookie_name","document","cookie","cookieRegex","RegExp","match","split","Ajax","csrfToken","CSRF_COOKIE_NAME","runningGets","ajax","method","data","progress","promise","deferred","ajax_settings","headers","X-CSRFToken","dataType","success","resolve","error","jqXHR","rejection","responseJSON","status","statusText","reject","$","preloaded","post","patch","put","filtersUrl","filters","encodedKey","encodeURIComponent","encodedValue","join","Query","call","path","related","model","relation","endpoint","then","results","map","models","Api","argumentsArray","arguments","apply","settings","mount","getElementById","ForumLayout","Models","classes","deserializers","relations","kwargs","deserialize","json","locale","attr","noop","route","isActive","__controller","controller","__onunload","onunload","vm","__init","initArgs","ondata","finalArgs","f","container","router","errorPage","loading","__view","view","isReady","Router","baseUrl","staticUrl","mediaUrl","urls","reverses","routedComponent","populatePatterns","urlconf","finalPattern","startRouting","mode","delegateElement","delegateName","cleanUrl","isRelative","substr","location","protocol","host","avatarsUrl","delegateClicks","element","on","e","target","href","preventDefault","off","prefixUrl","error403","ban","ErrorBannedRoute","detail","Error403Route","error404","Error404Route","error500","Error500Route","error0","Error0Route","RunLoop","_intervals","stopInterval","clearTimeout","run","callable","delay","setTimeout","result","runOnce","stop","loop","runloop","ticks","prop","startComputation","endComputation","PageTitle","forum_name","set","title","_set_complex","completeTitle","page","page_label","interpolate","gettext","parent","Ban","html","plain","expires_on","deserializeBan","class","LegalPage","body","error_message","help","code","icon","trust","expirationMessage","isAfter","fromNow","IndexRoute","forum_index_title","count","increment","console","log","ctrl","onclick","legalPageFactory","typeName","defaultTitle","dashedTypeName","PageHeader","Markup","TermsOfServiceRoute","PrivacyPolicyRoute","legalLink","legalType","FooterNav","isVisible","forum_footnote","terms_of_service","terms_of_service_link","privacy_policy","privacy_policy_link","ForumFooter","nav","FooterMisagoBranding","BrandFull","branding","children","src","alt","ForumNavbar","desktopNavbar","forum_branding_display","forum_branding_text","config","navbarStyle","persistent","el","isInit","retain","LoadingPage","setupMarkup","content","options"],"mappings":"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","file":"misago.js","sourcesContent":["/* global -Misago */\n/* exported Misago */\n(function () {\n  'use strict';\n\n  window.Misago = function() {\n    var ns = Object.getPrototypeOf(this);\n    var self = this;\n\n    // Context data\n    this.context = {\n      // Empty settings\n      SETTINGS: {}\n    };\n\n    // Services init/destroy\n    this._initServices = function(services) {\n      var orderedServices = new ns.OrderedList(services).order(false);\n      orderedServices.forEach(function (item) {\n        var factory = null;\n        if (item.item.factory !== undefined) {\n          factory = item.item.factory;\n        } else {\n          factory = item.item;\n        }\n\n        var serviceInstance = factory(self);\n        if (serviceInstance) {\n          self[item.key] = serviceInstance;\n        }\n      });\n    };\n\n    this._destroyServices = function(services) {\n      var orderedServices = new ns.OrderedList(services).order();\n      orderedServices.reverse();\n      orderedServices.forEach(function (item) {\n        if (item.destroy !== undefined) {\n          item.destroy(self);\n        }\n      });\n    };\n\n    // App init/destory\n    this.setup = false;\n    this.init = function(setup) {\n      this.setup = {\n        fixture: ns.get(setup, 'fixture', null),\n        inTest: ns.get(setup, 'inTest', false),\n        api: ns.get(setup, 'api', '/api/')\n      };\n\n      this._initServices(ns._services);\n    };\n\n    this.destroy = function() {\n      this._destroyServices(ns._services);\n    };\n  };\n\n\n  // Services registry\n  var proto = window.Misago.prototype;\n  proto._services = [];\n\n  proto.addService = function(name, factory, order) {\n    proto._services.push({\n      key: name,\n      item: factory,\n      after: proto.get(order, 'after'),\n      before: proto.get(order, 'before')\n    });\n  };\n}());\n\n(function (Misago) {\n  'use strict';\n\n  Misago.has = function(obj, key) {\n    if (obj) {\n      return obj.hasOwnProperty(key);\n    } else {\n      return false;\n    }\n  };\n\n  Misago.get = function(obj, key, value) {\n    if (Misago.has(obj, key)) {\n      return obj[key];\n    } else if (value !== undefined) {\n      return value;\n    } else {\n      return undefined;\n    }\n  };\n\n  Misago.pop = function(obj, key, value) {\n    var returnValue = Misago.get(obj, key, value);\n    if (Misago.has(obj, key)) {\n      obj[key] = null;\n    }\n    return returnValue;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.OrderedList = function(items) {\n    this.isOrdered = false;\n    this._items = items || [];\n\n    this.add = function(key, item, order) {\n      this._items.push({\n        key: key,\n        item: item,\n        after: Misago.get(order, 'after'),\n        before: Misago.get(order, 'before')\n      });\n    };\n\n    this.get = function(key, value) {\n      for (var i = 0; i < this._items.length; i++) {\n        if (this._items[i].key === key) {\n          return this._items[i].item;\n        }\n      }\n\n      return value;\n    };\n\n    this.has = function(key) {\n      return this.get(key) !== undefined;\n    };\n\n    this.values = function() {\n      var values = [];\n      for (var i = 0; i < this._items.length; i++) {\n        values.push(this._items[i].item);\n      }\n      return values;\n    };\n\n    this.order = function(values_only) {\n      if (!this.isOrdered) {\n        this._items = this._order(this._items);\n        this.isOrdered = true;\n      }\n\n      if (values_only || typeof values_only === 'undefined') {\n        return this.values();\n      } else {\n        return this._items;\n      }\n    };\n\n    this._order = function(unordered) {\n      // Index of unordered items\n      var index = [];\n      unordered.forEach(function (item) {\n        index.push(item.key);\n      });\n\n      // Ordered items\n      var ordered = [];\n      var ordering = [];\n\n      // First pass: register items that\n      // don't specify their order\n      unordered.forEach(function (item) {\n        if (!item.after && !item.before) {\n          ordered.push(item);\n          ordering.push(item.key);\n        }\n      });\n\n      // Second pass: register items that\n      // specify their before to \"_end\"\n      unordered.forEach(function (item) {\n        if (item.before === \"_end\") {\n          ordered.push(item);\n          ordering.push(item.key);\n        }\n      });\n\n      // Third pass: keep iterating items\n      // until we hit iterations limit or finish\n      // ordering list\n      function insertItem(item) {\n        var insertAt = -1;\n        if (ordering.indexOf(item.key) === -1) {\n          if (item.after) {\n            insertAt = ordering.indexOf(item.after);\n            if (insertAt !== -1) {\n              insertAt += 1;\n            }\n          } else if (item.before) {\n            insertAt = ordering.indexOf(item.before);\n          }\n\n          if (insertAt !== -1) {\n            ordered.splice(insertAt, 0, item);\n            ordering.splice(insertAt, 0, item.key);\n          }\n        }\n      }\n\n      var iterations = 200;\n      while (iterations > 0 && index.length !== ordering.length) {\n        iterations -= 1;\n        unordered.forEach(insertItem);\n      }\n\n      return ordered;\n    };\n  };\n} (Misago.prototype));\n\n(function (Misago) {\n  Misago.serializeDatetime = function(serialized) {\n    return serialized ? serialized.format() : null;\n  };\n\n  Misago.deserializeDatetime = function(deserialized) {\n    return deserialized ? moment(deserialized) : null;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.startsWith = function(string, beginning) {\n    return string.indexOf(beginning) === 0;\n  };\n\n  Misago.endsWith = function(string, tail) {\n    return string.indexOf(tail, string.length - tail.length) !== -1;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.UrlConfInvalidComponentError = function(name) {\n    this.message = \"route's \" + name + \" component \" +\n                   \"should be an array or object\";\n\n    this.toString = function() {\n      return this.message;\n    };\n  };\n\n  Misago.UrlConf = function() {\n    var self = this;\n    this._patterns = [];\n\n    this.patterns = function() {\n      return this._patterns;\n    };\n\n    var prefixPattern = function(prefix, pattern) {\n      return (prefix + pattern).replace('//', '/');\n    };\n\n    var include = function(prefix, patterns) {\n      for (var i = 0; i < patterns.length; i ++) {\n        self.url(prefixPattern(prefix, patterns[i].pattern),\n                 patterns[i].component,\n                 patterns[i].name);\n      }\n    };\n\n    this.url = function(pattern, component, name) {\n      if (typeof component !== 'object') {\n        throw new Misago.UrlConfInvalidComponentError(name);\n      }\n\n      if (pattern === '') {\n        pattern = '/';\n      }\n\n      if (component instanceof Misago.UrlConf) {\n        include(pattern, component.patterns());\n      } else {\n        this._patterns.push({\n          pattern: pattern,\n          component: component,\n          name: name\n        });\n      }\n    };\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.loadingPage = function(_) {\n    return m('.page.page-loading',\n      _.component(Misago.Loader)\n    );\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var getCsrfToken = function(cookie_name) {\n    if (document.cookie.indexOf(cookie_name) !== -1) {\n      var cookieRegex = new RegExp(cookie_name + '\\=([^;]*)');\n      var cookie = Misago.get(document.cookie.match(cookieRegex), 0);\n      return cookie.split('=')[1];\n    } else {\n      return null;\n    }\n  };\n\n  var Ajax = function(_) {\n    this.csrfToken = getCsrfToken(_.context.CSRF_COOKIE_NAME);\n\n    /*\n      List of GETs underway\n      We are limiting number of GETs to API to 1 per url\n    */\n    var runningGets = {};\n\n    this.ajax = function(method, url, data, progress) {\n      var promise = m.deferred();\n\n      var ajax_settings = {\n        url: url,\n        method: method,\n        headers: {\n          'X-CSRFToken': this.csrfToken\n        },\n\n        data: data | {},\n        dataType: 'json',\n\n        success: function(data) {\n          if (method === 'GET') {\n            Misago.pop(runningGets, url);\n          }\n          promise.resolve(data);\n        },\n        error: function(jqXHR) {\n          if (method === 'GET') {\n            Misago.pop(runningGets, url);\n          }\n\n          var rejection = jqXHR.responseJSON || {};\n\n          rejection.status = jqXHR.status;\n          rejection.statusText = jqXHR.statusText;\n\n          promise.reject(rejection);\n        }\n      };\n\n      if (progress) {\n        return; // not implemented... yet!\n      }\n\n      $.ajax(ajax_settings);\n      return promise.promise;\n    };\n\n    this.get = function(url) {\n      var preloaded = Misago.pop(_.context, url);\n      if (preloaded) {\n        var deferred = m.deferred();\n        deferred.resolve(preloaded);\n        return deferred.promise;\n      } else if (runningGets[url] !== undefined) {\n        return runningGets[url];\n      } else {\n        runningGets[url] = this.ajax('GET', url);\n        return runningGets[url];\n      }\n    };\n\n    this.post = function(url, data) {\n      return this.ajax('POST', url, data);\n    };\n\n    this.patch = function(url, data) {\n      return this.ajax('PATCH', url, data);\n    };\n\n    this.put = function(url, data) {\n      return this.ajax('PUT', url, data);\n    };\n\n    this.delete = function(url) {\n      return this.ajax('DELETE', url);\n    };\n  };\n\n  Misago.addService('ajax', function(_) {\n    return new Ajax(_);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var filtersUrl = function(filters) {\n    if (typeof filters === 'object') {\n      var values = [];\n      for (var key in filters) {\n        if (filters.hasOwnProperty(key)) {\n          var encodedKey = encodeURIComponent(key);\n          var encodedValue = encodeURIComponent(filters[key]);\n          values.push(encodedKey + '=' + encodedValue);\n        }\n      }\n      return '?' + values.join('&');\n    } else {\n      return filters + '/';\n    }\n  };\n\n  var Query = function(_, call) {\n    this.url = call.url || _.setup.api;\n\n    if (call.path) {\n      this.url += call.path + '/';\n    } else if (call.related) {\n      this.url += call.related + '/';\n    } else {\n      this.url += call.model + 's' + '/';\n    }\n\n    if (call.filters) {\n      this.url += filtersUrl(call.filters);\n    }\n\n    if (!call.url && call.filters) {\n      if (call.model) {\n        this.related = function(model, filters) {\n          return new Query(_, {\n            url: this.url,\n            relation: call.model,\n            related: model,\n            filters: filters,\n          });\n        };\n      }\n\n      this.endpoint = function(path, filters) {\n        return new Query(_, {\n          url: this.url,\n          path: path,\n          filters: filters\n        });\n      };\n    }\n\n    this.get = function() {\n      var model = null;\n      if (call.related) {\n        model = call.relation + ':' + call.related;\n      } else if (call.model) {\n        model = call.model;\n      }\n\n      return _.ajax.get(this.url).then(function(data) {\n        if (model) {\n          if (data.results) {\n            data.results.map(function(item) {\n              return _.models.new(model, item);\n            });\n            return data;\n          } else {\n            return _.models.new(model, data);\n          }\n        } else {\n          return data;\n        }\n      });\n    };\n\n    this.post = function(data) {\n      return _.ajax.post(this.url, data);\n    };\n\n    this.patch = function(data) {\n      return _.ajax.patch(this.url, data);\n    };\n\n    this.put = function(data) {\n      return _.ajax.put(this.url, data);\n    };\n\n    this.delete = function() {\n      return _.ajax.delete(this.url);\n    };\n\n    // shortcut for get()\n    this.then = function(resolve, reject) {\n      return this.get().then(resolve, reject);\n    };\n  };\n\n  var Api = function(_) {\n    this.model = function(model, filters) {\n      return new Query(_, {\n        model: model,\n        filters: filters,\n      });\n    };\n\n    this.endpoint = function(path, filters) {\n      return new Query(_, {\n        path: path,\n        filters: filters\n      });\n    };\n  };\n\n  Misago.addService('api', function(_) {\n    return new Api(_);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('component-factory', function(_) {\n    // Component factory\n    _.component = function() {\n      var argumentsArray = [];\n      for (var i = 0; i < arguments.length; i += 1) {\n        argumentsArray.push(arguments[i]);\n      }\n\n      argumentsArray.push(_);\n      return m.component.apply(undefined, argumentsArray);\n    };\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('conf', function(_) {\n    _.settings = Misago.get(_.context, 'SETTINGS', {});\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('forum-layout', {\n    factory: function(_) {\n      if (_.setup.fixture) {\n        m.mount(document.getElementById(_.setup.fixture),\n                _.component(Misago.ForumLayout));\n      }\n    },\n\n    destroy: function(_) {\n      if (_.setup.fixture) {\n        m.mount(_.setup.fixture, null);\n      }\n    }\n  }, {before: 'start-routing'});\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Models = function() {\n    this.classes = {};\n    this.deserializers = {};\n    this.relations = {};\n\n    this.add = function(name, kwargs) {\n      if (kwargs.class) {\n        this.classes[name] = kwargs.class;\n      }\n\n      if (kwargs.deserialize) {\n        this.deserializers[name] = kwargs.deserialize;\n      }\n\n      if (kwargs.relations) {\n        for (var key in kwargs.relations) {\n          if (kwargs.relations.hasOwnProperty(key)) {\n            this.relations[name + ':' + key] = kwargs.relations[key];\n          }\n        }\n      }\n    };\n\n    this.new = function(name, data) {\n      if (this.classes[name]) {\n        return new this.classes[name](data);\n      } else {\n        return data;\n      }\n    };\n\n    this.deserialize = function(name, json) {\n      if (this.relations[name]) {\n        name = this.relations[name];\n      }\n\n      if (this.deserializers[name]) {\n        return this.new(name, this.deserializers[name](json, this));\n      } else {\n        return this.new(name, json);\n      }\n    };\n  };\n\n  Misago.addService('models', function() {\n    return new Models();\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('set-momentjs-locale', function() {\n    moment.locale($('html').attr('lang'));\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var noop = function() {};\n\n  Misago.route = function(component) {\n    /*\n      Boilerplate for Misago top-level components\n    */\n\n    // Component state\n    component.isActive = true;\n\n    // Wrap controller to store lifecycle methods\n    var __controller = component.controller || noop;\n    component.controller = function() {\n      component.isActive = true;\n\n      var controller = __controller.apply(component, arguments) || {};\n\n      // wrap onunload for lifestate\n      var __onunload = controller.onunload || noop;\n      controller.onunload = function() {\n        __onunload.apply(component, arguments);\n        component.isActive = false;\n      };\n\n      return controller;\n    };\n\n    // Add state callbacks to View-Model\n    if (component.vm && component.vm.init) {\n      // wrap vm.init in promise handler\n      var __init = component.vm.init;\n      component.vm.init = function() {\n        var initArgs = arguments;\n        var promise = __init.apply(component.vm, initArgs);\n\n        if (promise) {\n          promise.then(function() {\n            if (component.isActive && component.vm.ondata) {\n              var finalArgs = [];\n              for (var i = 0; i < arguments.length; i++) {\n                finalArgs.push(arguments[i]);\n              }\n              for (var f = 0; f < initArgs.length; f++) {\n                finalArgs.push(initArgs[f]);\n              }\n\n              component.vm.ondata.apply(component.vm, finalArgs);\n            }\n          }, function(error) {\n            if (component.isActive) {\n              component.container.router.errorPage(error);\n            }\n          });\n        }\n      };\n\n      // setup default loading view\n      if (!component.loading) {\n        component.loading = function () {\n          var _ = this.container;\n          return m('.page.page-loading',\n            _.component(Misago.Loader)\n          );\n        };\n      }\n\n      var __view = component.view;\n      component.view = function() {\n        if (component.vm.isReady) {\n          return __view.apply(component, arguments);\n        } else {\n          return component.loading.apply(component, arguments);\n        }\n      };\n    }\n\n    return component;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Router = function(_) {\n    var self = this;\n    this.baseUrl = $('base').attr('href');\n\n    var staticUrl = Misago.get(_.context, 'STATIC_URL', '/');\n    var mediaUrl = Misago.get(_.context, 'MEDIA_URL', '/');\n\n    // Routing\n    this.urls = {};\n    this.reverses = {};\n\n    var routedComponent = function(component) {\n      component.container = _;\n      return component;\n    };\n\n    var populatePatterns = function(urlconf) {\n      urlconf.patterns().forEach(function(url) {\n        // set service container on component\n\n        var finalPattern = self.baseUrl + url.pattern;\n        finalPattern = finalPattern.replace('//', '/');\n\n        self.urls[finalPattern] = routedComponent(url.component);\n        self.reverses[url.name] = finalPattern;\n      });\n    };\n\n    this.startRouting = function(urlconf, fixture) {\n      populatePatterns(urlconf);\n      this.fixture = fixture;\n\n      m.route.mode = 'pathname';\n      m.route(fixture, '/', this.urls);\n    };\n\n    this.url = function(name) {\n      return this.reverses[name];\n    };\n\n    // Delegate clicks\n    this.delegateElement = null;\n    this.delegateName = 'click.misago-router';\n\n    this.cleanUrl = function(url) {\n      if (!url) { return; }\n\n      // Is link relative?\n      var isRelative = url.substr(0, 1) === '/' && url.substr(0, 2) !== '//';\n\n      // If link contains host, validate to see if its outgoing\n      if (!isRelative) {\n        var location = window.location;\n\n        // If protocol matches current one, strip it from string\n        // otherwhise stop handler\n        if (url.substr(0, 2) !== '//') {\n          var protocol = url.substr(0, location.protocol.length + 2);\n          if (protocol !== location.protocol + '//') { return; }\n          url = url.substr(location.protocol.length + 2);\n        } else {\n          url = url.substr(2);\n        }\n\n        // Host checks out?\n        if (url.substr(0, location.host.length) !== location.host) { return; }\n        url = url.substr(location.host.length);\n      }\n\n      // Is link within Ember app?\n      if (url.substr(0, this.baseUrl.length) !== this.baseUrl) { return; }\n\n      // Is link to media/static/avatar server?\n      if (url.substr(0, staticUrl.length) === staticUrl) { return; }\n\n      if (url.substr(0, mediaUrl.length) === mediaUrl) { return; }\n\n      var avatarsUrl = '/user-avatar/';\n      if (url.substr(0, avatarsUrl.length) === avatarsUrl) { return; }\n\n      return url;\n    };\n\n    this.delegateClicks = function(element) {\n      this.delegateElement = element;\n      $(this.delegateElement).on(this.delegateName, 'a', function(e) {\n        var cleanUrl = self.cleanUrl(e.target.href);\n        if (cleanUrl) {\n          if (cleanUrl != m.route()) {\n            m.route(cleanUrl);\n          }\n          e.preventDefault();\n        }\n      });\n    };\n\n    this.destroy = function() {\n      $(this.delegateElement).off(this.delegateName);\n    };\n\n    // Media/Static url\n    var prefixUrl = function(prefix) {\n      return function(url) {\n        return prefix + url;\n      };\n    };\n\n    this.staticUrl = prefixUrl(staticUrl);\n    this.mediaUrl = prefixUrl(mediaUrl);\n\n    // Errors\n    this.error403 = function(error) {\n      var component = null;\n      if (error.ban) {\n        component = routedComponent(Misago.ErrorBannedRoute);\n        component.error = {\n          message: error.detail,\n          ban: _.models.deserialize('ban', error.ban)\n        };\n      } else {\n        component = routedComponent(Misago.Error403Route);\n        component.error = error.detail;\n      }\n\n      m.mount(this.fixture, component);\n    };\n\n    this.error404 = function() {\n      m.mount(this.fixture, routedComponent(Misago.Error404Route));\n    };\n\n    this.error500 = function() {\n      m.mount(this.fixture, routedComponent(Misago.Error500Route));\n    };\n\n    this.error0 = function() {\n      m.mount(this.fixture, routedComponent(Misago.Error0Route));\n    };\n\n    this.errorPage = function(error) {\n      if (error.status === 0) {\n        this.error0();\n      }\n\n      if (error.status === 500) {\n        this.error500();\n      }\n\n      if (error.status === 404) {\n        this.error404();\n      }\n\n      if (error.status === 403) {\n        this.error403(error);\n      }\n    };\n  };\n\n  Misago.addService('router', function(_) {\n    return new Router(_);\n  });\n\n  Misago.addService('start-routing', function(_) {\n    _.router.startRouting(\n      Misago.urls, document.getElementById('router-fixture'));\n    _.router.delegateClicks(document.getElementById(_.setup.fixture));\n  }, {before: '_end'});\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var RunLoop = function(_) {\n    var self = this;\n\n    this._intervals = {};\n\n    var stopInterval = function(name) {\n      if (self._intervals[name]) {\n        window.clearTimeout(self._intervals[name]);\n        self._intervals[name] = null;\n      }\n    };\n\n    this.run = function(callable, name, delay) {\n      this._intervals[name] = window.setTimeout(function() {\n        stopInterval(name);\n        var result = callable(_);\n        if (result !== false) {\n          self.run(callable, name, delay);\n        }\n      }, delay);\n    };\n\n    this.runOnce = function(callable, name, delay) {\n      this._intervals[name] = window.setTimeout(function() {\n        stopInterval(name);\n        callable(_);\n      }, delay);\n    };\n\n    this.stop = function(name) {\n      for (var loop in this._intervals) {\n        if (!name || name === loop) {\n          stopInterval(loop);\n        }\n      }\n    };\n  };\n\n  Misago.addService('runloop', {\n    factory: function(_) {\n      return new RunLoop(_);\n    },\n\n    destroy: function(_) {\n      _.runloop.stop();\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('start-tick', function(_) {\n    var ticks = m.prop();\n\n    _.runloop.run(function() {\n      m.startComputation();\n      // just tick once a minute so stuff gets rerendered\n      ticks(ticks() + 1);\n      // syncing dynamic timestamps, etc ect\n      m.endComputation();\n    }, 'tick', 60000);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var PageTitle = function(forum_name) {\n    this.set = function(title) {\n      if (title) {\n        this._set_complex(title);\n      } else {\n        document.title = forum_name;\n      }\n    };\n\n    this._set_complex = function(title) {\n      if (typeof title === 'string') {\n        title = {title: title};\n      }\n\n      var completeTitle = title.title;\n\n      if (typeof title.page !== 'undefined' && title.page > 1) {\n        var page_label = interpolate(\n          gettext('page %(page)s'), { page:title.page }, true);\n        completeTitle += ' (' + page_label + ')';\n      }\n\n      if (typeof title.parent !== 'undefined') {\n        completeTitle += ' | ' + title.parent;\n      }\n\n      document.title = completeTitle + ' | ' + forum_name;\n    };\n  };\n\n  Misago.addService('page-title', function(_) {\n    _.title = new PageTitle(_.settings.forum_name);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Ban = function(data) {\n    this.message = {\n      html: data.message.html,\n      plain: data.message.plain,\n    };\n\n    this.expires_on = data.expires_on;\n  };\n\n  var deserializeBan = function(data) {\n    data.expires_on = Misago.deserializeDatetime(data.expires_on);\n\n    return new Misago.Ban(data);\n  };\n\n  Misago.addService('ban-model', function(_) {\n    _.models.add('ban', {\n      class: Ban,\n      deserialize: deserializeBan\n    });\n  }, {after: 'models'});\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var LegalPage = function(data) {\n    this.title = data.title;\n    this.body = data.body;\n  };\n\n  Misago.addService('legal-page-model', function(_) {\n    _.models.add('legal-page', {\n      class: LegalPage\n    });\n  }, {after: 'models'});\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var errorPage = function(error) {\n    var error_message = [\n      m('p.lead', error.message)\n    ];\n\n    if (error.help) {\n      error_message.push(m('p.help', error.help));\n    }\n\n    return m('.page.error-page.error-' + error.code + '-page',\n      m('.container',\n        m('.error-panel', [\n          m('.error-icon',\n            m('span.material-icon', error.icon)\n          ),\n          m('.error-message', error_message)\n        ])\n      )\n    );\n  };\n\n  Misago.ErrorBannedRoute = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('You are banned'));\n    },\n    error: null,\n    view: function() {\n      var error_message = [];\n      if (this.error.ban.message.html) {\n        error_message.push(m('.lead', m.trust(this.error.ban.message.html)));\n      } else {\n        error_message.push(m('p.lead', this.error.message));\n      }\n\n      var expirationMessage = null;\n      if (this.error.ban.expires_on) {\n        if (this.error.ban.expires_on.isAfter(moment())) {\n          expirationMessage = interpolate(\n            gettext('This ban expires %(expires_on)s.'),\n            { 'expires_on': this.error.ban.expires_on.fromNow() },\n            true);\n        } else {\n          expirationMessage = gettext('This ban has expired.');\n        }\n      } else {\n        expirationMessage = gettext('This ban is permanent.');\n      }\n      error_message.push(m('p', expirationMessage));\n\n      return m('.page.error-page.error-banned-page',\n        m('.container',\n          m('.error-panel', [\n            m('.error-icon',\n              m('span.material-icon', 'highlight_off')\n            ),\n            m('.error-message', error_message)\n          ])\n        )\n      );\n    }\n  });\n\n  Misago.Error403Route = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('Page not available'));\n    },\n    error: null,\n    view: function() {\n      return errorPage({\n        code: 403,\n        icon: 'remove_circle_outline',\n        message: gettext(\"This page is not available.\"),\n        help: this.error || gettext(\"You don't have permission to access this page.\")\n      });\n    }\n  });\n\n  Misago.Error404Route = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('Page not found'));\n    },\n    view: function() {\n      return errorPage({\n        code: 404,\n        icon: 'info_outline',\n        message: gettext(\"Requested page could not be found.\"),\n        help: gettext(\"The link you followed was incorrect or the page has been moved or deleted.\")\n      });\n    }\n  });\n\n  Misago.Error500Route = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('Application error occured'));\n    },\n    view: function() {\n      return errorPage({\n        code: 500,\n        icon: 'error_outline',\n        message: gettext(\"Requested page could not be displayed due to an error.\"),\n        help: gettext(\"Please try again later or contact site staff if error persists.\")\n      });\n    }\n  });\n\n  Misago.Error0Route = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('Lost connection with application'));\n    },\n    view: function() {\n      return errorPage({\n        code: 500,\n        icon: 'sync_problem',\n        message: gettext(\"Could not connect to application.\"),\n        help: gettext(\"This may be caused by problems with your connection or application server. Please check your internet connection and refresh page if problem persists.\")\n      });\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.IndexRoute = Misago.route({\n    controller: function() {\n      var _ = this.container;\n      document.title = _.settings.forum_index_title || _.settings.forum_name;\n\n      var count = m.prop(0);\n\n      return {\n        count: count,\n        increment: function() {\n          console.log('increment()');\n          count(count() + 1);\n        }\n      };\n    },\n    view: function(ctrl) {\n      return m('.container', [\n        m('h1', [\n          'Count: ', m('strong', ctrl.count())\n        ]),\n        m('p', 'Clicky click button to increase count!.'),\n        m('p',\n          m('button.btn.btn-primary', {onclick: ctrl.increment},\n            'Clicky clicky!'\n          )\n        )\n      ]);\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var legalPageFactory = function(typeName, defaultTitle) {\n    var dashedTypeName = typeName.replace(/_/g, '-');\n\n    return Misago.route({\n      controller: function() {\n        var _ = this.container;\n\n        if (Misago.get(_.settings, typeName + '_link')) {\n          window.location = Misago.get(_.settings, typeName + '_link');\n        } else {\n          this.vm.init(this, _);\n        }\n      },\n      vm: {\n        page: null,\n        isReady: false,\n        init: function(component, _) {\n          if (this.isReady) {\n            _.title.set(this.title);\n          } else {\n            _.title.set();\n            return _.api.model('legal-page', dashedTypeName);\n          }\n        },\n        ondata: function(page, component, _) {\n          m.startComputation();\n\n          page.title = page.title || defaultTitle;\n          this.page = page;\n          this.isReady = true;\n\n          m.endComputation();\n\n          if (component.isActive) {\n            _.title.set(this.page.title);\n          }\n        }\n      },\n      view: function() {\n        var _ = this.container;\n\n        return m('.page.legal-page.' + dashedTypeName + '-page', [\n          _.component(Misago.PageHeader, {title: this.vm.page.title}),\n          m('.container',\n            _.component(Misago.Markup, this.vm.page.body)\n          )\n        ]);\n      }\n    });\n  };\n\n  Misago.TermsOfServiceRoute = legalPageFactory(\n    'terms_of_service', gettext('Terms of service'));\n  Misago.PrivacyPolicyRoute = legalPageFactory(\n    'privacy_policy', gettext('Privacy policy'));\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var legalLink = function(_, legalType, defaultTitle) {\n    var url = Misago.get(_.settings, legalType + '_link');\n    if (!url && Misago.get(_.settings, legalType)) {\n      url = _.router.url(legalType);\n    }\n\n    if (url) {\n      return m('li',\n        m('a', {href: url},\n          Misago.get(_.settings, legalType + '_title', defaultTitle)\n        )\n      );\n    } else {\n      return null;\n    }\n  };\n\n  Misago.FooterNav = {\n    isVisible: function(settings) {\n      return [\n        !!settings.forum_footnote,\n        !!settings.terms_of_service,\n        !!settings.terms_of_service_link,\n        !!settings.privacy_policy,\n        !!settings.privacy_policy_link\n      ].indexOf(true) !== -1;\n    },\n    view: function(ctrl, _) {\n      var items = [];\n\n      if (_.settings.forum_footnote) {\n        items.push(m('li.forum-footnote', m.trust(_.settings.forum_footnote)));\n      }\n\n      items.push(\n        legalLink(_, 'terms_of_service', gettext('Terms of service')));\n      items.push(\n        legalLink(_, 'privacy_policy', gettext('Privacy policy')));\n\n      return m('ul.list-inline.footer-nav', items);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.ForumFooter = {\n    view: function(ctrl, _) {\n      var nav = null;\n      if (Misago.FooterNav.isVisible(_.settings)) {\n        nav = _.component(Misago.FooterNav);\n      }\n\n      return m('footer.forum-footer', [\n        m('.container',\n          m('.footer-content', [\n            nav,\n            _.component(Misago.FooterMisagoBranding)\n          ])\n        )\n      ]);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.FooterMisagoBranding = {\n    view: function() {\n      return m('a.misago-branding[href=http://misago-project.org]', [\n        \"powered by \", m('strong', \"misago\")\n      ]);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.BrandFull = {\n    view: function(ctrl, branding, _) {\n      var children = [\n        m('img', {\n          src: _.router.staticUrl('misago/img/site-logo.png'),\n          alt: _.settings.forum_name\n        })\n      ];\n\n      if (branding) {\n        children.push(branding);\n      }\n\n      return m('a.navbar-brand', {href: _.router.url('index')}, children);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.ForumNavbar = {\n    view: function(ctrl, _) {\n      var desktopNavbar = [];\n\n      if (_.settings.forum_branding_display) {\n        desktopNavbar.push(\n          _.component(Misago.BrandFull, _.settings.forum_branding_text));\n      }\n\n      desktopNavbar.push(m('ul.nav.navbar-nav', [\n        m('li',\n          m(\"a\", {config: m.route, href: _.router.url('index')}, 'Index')\n        )\n      ]));\n\n      var navbarStyle = '.navbar.navbar-default.navbar-static-top';\n\n      return m('nav' + navbarStyle + '[role=\"navigation\"]', [\n        m('.container.navbar-full.hidden-xs.hidden-sm', desktopNavbar)\n      ]);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var persistent = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  Misago.ForumLayout = {\n    view: function(ctrl, _) {\n      return [\n        _.component(Misago.ForumNavbar),\n        m('#router-fixture', {config: persistent}),\n        _.component(Misago.ForumFooter)\n      ];\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.Loader = {\n    view: function() {\n      return m('.loader.sk-folding-cube', [\n        m('.sk-cube1.sk-cube'),\n        m('.sk-cube2.sk-cube'),\n        m('.sk-cube4.sk-cube'),\n        m('.sk-cube3.sk-cube')\n      ]);\n    }\n  };\n\n  Misago.LoadingPage = {\n    view: function(ctrl, _) {\n      return m('.page.loading-page',\n        _.component(Misago.Loader)\n      );\n    }\n  };\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var setupMarkup = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  Misago.Markup = {\n    view: function(ctrl, content) {\n      return m('article.misago-markup', {config: setupMarkup},\n        m.trust(content)\n      );\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.PageHeader = {\n    view: function(ctrl, options) {\n      return m('.page-header',\n        m('.container', [\n          m('h1', options.title),\n        ])\n      );\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago, UrlConf) {\n  'use strict';\n\n  var urls = new UrlConf();\n  urls.url('/', Misago.IndexRoute, 'index');\n\n  // Legal pages\n  urls.url(\n    '/terms-of-service/',\n    Misago.TermsOfServiceRoute,\n    'terms_of_service');\n\n  urls.url(\n    '/privacy-policy/',\n    Misago.PrivacyPolicyRoute,\n    'privacy_policy');\n\n  Misago.urls = urls;\n} (Misago.prototype, Misago.prototype.UrlConf));\n"],"sourceRoot":"/source/"}

+ 2 - 1
misago/templates/misago/base.html

@@ -48,7 +48,8 @@
       var misago = new Misago();
       {% include "misago/frontend_context.js" %}
       misago.init({
-        fixture: 'misago-fixture'
+        fixture: 'misago-fixture',
+        api: '{% url 'misago:api:api-root' %}'
       });
     </script>