PageSourceSearch

https://alpfederation.ru/assets/js/bundles/app.js?v32?r=1790961560

js alpfederation.ru collected 2026-10-02 17:19:53 UTC 1,172,550 bytes, 35,459 lines download raw bytes

1(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2/**
3 * @license AngularJS v1.4.14
4 * (c) 2010-2015 Google, Inc. http://angularjs.org
5 * License: MIT
6 */
7(function(window, angular, undefined) {'use strict';
8
9var $resourceMinErr = angular.$$minErr('$resource');
10
11// Helper functions and regex to lookup a dotted path on an object
12// stopping at undefined/null.  The path must be composed of ASCII
13// identifiers (just like $parse)
14var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;
15
16function isValidDottedPath(path) {
17  return (path != null && path !== '' && path !== 'hasOwnProperty' &&
18      MEMBER_NAME_REGEX.test('.' + path));
19}
20
21function lookupDottedPath(obj, path) {
22  if (!isValidDottedPath(path)) {
23    throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path);
24  }
25  var keys = path.split('.');
26  for (var i = 0, ii = keys.length; i < ii && angular.isDefined(obj); i++) {
27    var key = keys[i];
28    obj = (obj !== null) ? obj[key] : undefined;
29  }
30  return obj;
31}
32
33/**
34 * Create a shallow copy of an object and clear other fields from the destination
35 */
36function shallowClearAndCopy(src, dst) {
37  dst = dst || {};
38
39  angular.forEach(dst, function(value, key) {
40    delete dst[key];
41  });
42
43  for (var key in src) {
44    if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
45      dst[key] = src[key];
46    }
47  }
48
49  return dst;
50}
51
52/**
53 * @ngdoc module
54 * @name ngResource
55 * @description
56 *
57 * # ngResource
58 *
59 * The `ngResource` module provides interaction support with RESTful services
60 * via the $resource service.
61 *
62 *
63 * <div doc-module-components="ngResource"></div>
64 *
65 * See {@link ngResource.$resource `$resource`} for usage.
66 */
67
68/**
69 * @ngdoc service
70 * @name $resource
71 * @requires $http
72 *
73 * @description
74 * A factory which creates a resource object that lets you interact with
75 * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
76 *
77 * The returned resource object has action methods which provide high-level behaviors without
78 * the need to interact with the low level {@link ng.$http $http} service.
79 *
80 * Requires the {@link ngResource `ngResource`} module to be installed.
81 *
82 * By default, trailing slashes will be stripped from the calculated URLs,
83 * which can pose problems with server backends that do not expect that
84 * behavior.  This can be disabled by configuring the `$resourceProvider` like
85 * this:
86 *
87 * ```js
88     app.config(['$resourceProvider', function($resourceProvider) {
89       // Don't strip trailing slashes from calculated URLs
90       $resourceProvider.defaults.stripTrailingSlashes = false;
91     }]);
92 * ```
93 *
94 * @param {string} url A parameterized URL template with parameters prefixed by `:` as in
95 *   `/user/:username`. If you are using a URL with a port number (e.g.
96 *   `http://example.com:8080/api`), it will be respected.
97 *
98 *   If you are using a url with a suffix, just add the suffix, like this:
99 *   `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
100 *   or even `$resource('http://example.com/resource/:resource_id.:format')`
101 *   If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
102 *   collapsed down to a single `.`.  If you need this sequence to appear and not collapse then you
103 *   can escape it with `/\.`.
104 *
105 * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
106 *   `actions` methods. If a parameter value is a function, it will be executed every time
107 *   when a param value needs to be obtained for a request (unless the param was overridden).
108 *
109 *   Each key value in the parameter object is first bound to url template if present and then any
110 *   excess keys are appended to the url search query after the `?`.
111 *
112 *   Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
113 *   URL `/path/greet?salutation=Hello`.
114 *
115 *   If the parameter value is prefixed with `@` then the value for that parameter will be extracted
116 *   from the corresponding property on the `data` object (provided when calling an action method).  For
117 *   example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of `someParam`
118 *   will be `data.someProp`.
119 *
120 * @param {Object.<Object>=} actions Hash with declaration of custom actions that should extend
121 *   the default set of resource actions. The declaration should be created in the format of {@link
122 *   ng.$http#usage $http.config}:
123 *
124 *       {action1: {method:?, params:?, isArray:?, headers:?, ...},
125 *        action2: {method:?, params:?, isArray:?, headers:?, ...},
126 *        ...}
127 *
128 *   Where:
129 *
130 *   - **`action`** – {string} – The name of action. This name becomes the name of the method on
131 *     your resource object.
132 *   - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`,
133 *     `DELETE`, `JSONP`, etc).
134 *   - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
135 *     the parameter value is a function, it will be executed every time when a param value needs to
136 *     be obtained for a request (unless the param was overridden).
137 *   - **`url`** – {string} – action specific `url` override. The url templating is supported just
138 *     like for the resource-level urls.
139 *   - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
140 *     see `returns` section.
141 *   - **`transformRequest`** –
142 *     `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
143 *     transform function or an array of such functions. The transform function takes the http
144 *     request body and headers and returns its transformed (typically serialized) version.
145 *     By default, transformRequest will contain one function that checks if the request data is
146 *     an object and serializes to using `angular.toJson`. To prevent this behavior, set
147 *     `transformRequest` to an empty array: `transformRequest: []`
148 *   - **`transformResponse`** –
149 *     `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
150 *     transform function or an array of such functions. The transform function takes the http
151 *     response body and headers and returns its transformed (typically deserialized) version.
152 *     By default, transformResponse will contain one function that checks if the response looks like
153 *     a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior, set
154 *     `transformResponse` to an empty array: `transformResponse: []`
155 *   - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
156 *     GET request, otherwise if a cache instance built with
157 *     {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
158 *     caching.
159 *   - **`timeout`** – `{number}` – timeout in milliseconds.<br />
160 *     **Note:** In contrast to {@link ng.$http#usage $http.config}, {@link ng.$q promises} are
161 *     **not** supported in $resource, because the same value would be used for multiple requests.
162 *     If you need support for cancellable $resource actions, you should upgrade to version 1.5 or
163 *     higher.
164 *   - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
165 *     XHR object. See
166 *     [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
167 *     for more information.
168 *   - **`responseType`** - `{string}` - see
169 *     [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
170 *   - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
171 *     `response` and `responseError`. Both `response` and `responseError` interceptors get called
172 *     with `http response` object. See {@link ng.$http $http interceptors}.
173 *
174 * @param {Object} options Hash with custom settings that should extend the
175 *   default `$resourceProvider` behavior.  The only supported option is
176 *
177 *   Where:
178 *
179 *   - **`stripTrailingSlashes`** – {boolean} – If true then the trailing
180 *   slashes from any calculated URL will be stripped. (Defaults to true.)
181 *
182 * @returns {Object} A resource "class" object with methods for the default set of resource actions
183 *   optionally extended with custom `actions`. The default set contains these actions:
184 *   ```js
185 *   { 'get':    {method:'GET'},
186 *     'save':   {method:'POST'},
187 *     'query':  {method:'GET', isArray:true},
188 *     'remove': {method:'DELETE'},
189 *     'delete': {method:'DELETE'} };
190 *   ```
191 *
192 *   Calling these methods invoke an {@link ng.$http} with the specified http method,
193 *   destination and parameters. When the data is returned from the server then the object is an
194 *   instance of the resource class. The actions `save`, `remove` and `delete` are available on it
195 *   as  methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
196 *   read, update, delete) on server-side data like this:
197 *   ```js
198 *   var User = $resource('/user/:userId', {userId:'@id'});
199 *   var user = User.get({userId:123}, function() {
200 *     user.abc = true;
201 *     user.$save();
202 *   });
203 *   ```
204 *
205 *   It is important to realize that invoking a $resource object method immediately returns an
206 *   empty reference (object or array depending on `isArray`). Once the data is returned from the
207 *   server the existing reference is populated with the actual data. This is a useful trick since
208 *   usually the resource is assigned to a model which is then rendered by the view. Having an empty
209 *   object results in no rendering, once the data arrives from the server then the object is
210 *   populated with the data and the view automatically re-renders itself showing the new data. This
211 *   means that in most cases one never has to write a callback function for the action methods.
212 *
213 *   The action methods on the class object or instance object can be invoked with the following
214 *   parameters:
215 *
216 *   - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
217 *   - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
218 *   - non-GET instance actions:  `instance.$action([parameters], [success], [error])`
219 *
220 *
221 *   Success callback is called with (value, responseHeaders) arguments, where the value is
222 *   the populated resource instance or collection object. The error callback is called
223 *   with (httpResponse) argument.
224 *
225 *   Class actions return empty instance (with additional properties below).
226 *   Instance actions return promise of the action.
227 *
228 *   The Resource instances and collection have these additional properties:
229 *
230 *   - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
231 *     instance or collection.
232 *
233 *     On success, the promise is resolved with the same resource instance or collection object,
234 *     updated with data from server. This makes it easy to use in
235 *     {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
236 *     rendering until the resource(s) are loaded.
237 *
238 *     On failure, the promise is rejected with the {@link ng.$http http response} object, without
239 *     the `resource` property.
240 *
241 *     If an interceptor object was provided, the promise will instead be resolved with the value
242 *     returned by the interceptor.
243 *
244 *   - `$resolved`: `true` after first server interaction is completed (either with success or
245 *      rejection), `false` before that. Knowing if the Resource has been resolved is useful in
246 *      data-binding.
247 *
248 * @example
249 *
250 * # Credit card resource
251 *
252 * ```js
253     // Define CreditCard class
254     var CreditCard = $resource('/user/:userId/card/:cardId',
255      {userId:123, cardId:'@id'}, {
256       charge: {method:'POST', params:{charge:true}}
257      });
258
259     // We can retrieve a collection from the server
260     var cards = CreditCard.query(function() {
261       // GET: /user/123/card
262       // server returns: [ {id:456, number:'1234', name:'Smith'} ];
263
264       var card = cards[0];
265       // each item is an instance of CreditCard
266       expect(card instanceof CreditCard).toEqual(true);
267       card.name = "J. Smith";
268       // non GET methods are mapped onto the instances
269       card.$save();
270       // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
271       // server returns: {id:456, number:'1234', name: 'J. Smith'};
272
273       // our custom method is mapped as well.
274       card.$charge({amount:9.99});
275       // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
276     });
277
278     // we can create an instance as well
279     var newCard = new CreditCard({number:'0123'});
280     newCard.name = "Mike Smith";
281     newCard.$save();
282     // POST: /user/123/card {number:'0123', name:'Mike Smith'}
283     // server returns: {id:789, number:'0123', name: 'Mike Smith'};
284     expect(newCard.id).toEqual(789);
285 * ```
286 *
287 * The object returned from this function execution is a resource "class" which has "static" method
288 * for each action in the definition.
289 *
290 * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
291 * `headers`.
292 * When the data is returned from the server then the object is an instance of the resource type and
293 * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
294 * operations (create, read, update, delete) on server-side data.
295
296   ```js
297     var User = $resource('/user/:userId', {userId:'@id'});
298     User.get({userId:123}, function(user) {
299       user.abc = true;
300       user.$save();
301     });
302   ```
303 *
304 * It's worth noting that the success callback for `get`, `query` and other methods gets passed
305 * in the response that came from the server as well as $http header getter function, so one
306 * could rewrite the above example and get access to http headers as:
307 *
308   ```js
309     var User = $resource('/user/:userId', {userId:'@id'});
310     User.get({userId:123}, function(u, getResponseHeaders){
311       u.abc = true;
312       u.$save(function(u, putResponseHeaders) {
313         //u => saved user object
314         //putResponseHeaders => $http header getter
315       });
316     });
317   ```
318 *
319 * You can also access the raw `$http` promise via the `$promise` property on the object returned
320 *
321   ```
322     var User = $resource('/user/:userId', {userId:'@id'});
323     User.get({userId:123})
324         .$promise.then(function(user) {
325           $scope.user = user;
326         });
327   ```
328
329 * # Creating a custom 'PUT' request
330 * In this example we create a custom method on our resource to make a PUT request
331 * ```js
332 *    var app = angular.module('app', ['ngResource', 'ngRoute']);
333 *
334 *    // Some APIs expect a PUT request in the format URL/object/ID
335 *    // Here we are creating an 'update' method
336 *    app.factory('Notes', ['$resource', function($resource) {
337 *    return $resource('/notes/:id', null,
338 *        {
339 *            'update': { method:'PUT' }
340 *        });
341 *    }]);
342 *
343 *    // In our controller we get the ID from the URL using ngRoute and $routeParams
344 *    // We pass in $routeParams and our Notes factory along with $scope
345 *    app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
346                                      function($scope, $routeParams, Notes) {
347 *    // First get a note object from the factory
348 *    var note = Notes.get({ id:$routeParams.id });
349 *    $id = note.id;
350 *
351 *    // Now call update passing in the ID first then the object you are updating
352 *    Notes.update({ id:$id }, note);
353 *
354 *    // This will PUT /notes/ID with the note object in the request payload
355 *    }]);
356 * ```
357 */
358angular.module('ngResource', ['ng']).
359  provider('$resource', function() {
360    var PROTOCOL_AND_DOMAIN_REGEX = /^https?:\/\/[^\/]*/;
361    var provider = this;
362
363    this.defaults = {
364      // Strip slashes by default
365      stripTrailingSlashes: true,
366
367      // Default actions configuration
368      actions: {
369        'get': {method: 'GET'},
370        'save': {method: 'POST'},
371        'query': {method: 'GET', isArray: true},
372        'remove': {method: 'DELETE'},
373        'delete': {method: 'DELETE'}
374      }
375    };
376
377    this.$get = ['$http', '$log', '$q', function($http, $log, $q) {
378
379      var noop = angular.noop,
380        forEach = angular.forEach,
381        extend = angular.extend,
382        copy = angular.copy,
383        isFunction = angular.isFunction;
384
385      /**
386       * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
387       * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set
388       * (pchar) allowed in path segments:
389       *    segment       = *pchar
390       *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
391       *    pct-encoded   = "%" HEXDIG HEXDIG
392       *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
393       *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
394       *                     / "*" / "+" / "," / ";" / "="
395       */
396      function encodeUriSegment(val) {
397        return encodeUriQuery(val, true).
398          replace(/%26/gi, '&').
399          replace(/%3D/gi, '=').
400          replace(/%2B/gi, '+');
401      }
402
403
404      /**
405       * This method is intended for encoding *key* or *value* parts of query component. We need a
406       * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
407       * have to be encoded per http://tools.ietf.org/html/rfc3986:
408       *    query       = *( pchar / "/" / "?" )
409       *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
410       *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
411       *    pct-encoded   = "%" HEXDIG HEXDIG
412       *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
413       *                     / "*" / "+" / "," / ";" / "="
414       */
415      function encodeUriQuery(val, pctEncodeSpaces) {
416        return encodeURIComponent(val).
417          replace(/%40/gi, '@').
418          replace(/%3A/gi, ':').
419          replace(/%24/g, '$').
420          replace(/%2C/gi, ',').
421          replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
422      }
423
424      function Route(template, defaults) {
425        this.template = template;
426        this.defaults = extend({}, provider.defaults, defaults);
vendor: 5,522 bytes, lines 427-578
427        this.urlParams = {};
428      }
429
430      Route.prototype = {
431        setUrlParams: function(config, params, actionUrl) {
432          var self = this,
433            url = actionUrl || self.template,
434            val,
435            encodedVal,
436            protocolAndDomain = '';
437
438          var urlParams = self.urlParams = {};
439          forEach(url.split(/\W/), function(param) {
440            if (param === 'hasOwnProperty') {
441              throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
442            }
443            if (!(new RegExp("^\\d+$").test(param)) && param &&
444              (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
445              urlParams[param] = true;
446            }
447          });
448          url = url.replace(/\\:/g, ':');
449          url = url.replace(PROTOCOL_AND_DOMAIN_REGEX, function(match) {
450            protocolAndDomain = match;
451            return '';
452          });
453
454          params = params || {};
455          forEach(self.urlParams, function(_, urlParam) {
456            val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
457            if (angular.isDefined(val) && val !== null) {
458              encodedVal = encodeUriSegment(val);
459              url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
460                return encodedVal + p1;
461              });
462            } else {
463              url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
464                  leadingSlashes, tail) {
465                if (tail.charAt(0) == '/') {
466                  return tail;
467                } else {
468                  return leadingSlashes + tail;
469                }
470              });
471            }
472          });
473
474          // strip trailing slashes and set the url (unless this behavior is specifically disabled)
475          if (self.defaults.stripTrailingSlashes) {
476            url = url.replace(/\/+$/, '') || '/';
477          }
478
479          // then replace collapse `/.` if found in the last URL path segment before the query
480          // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
481          url = url.replace(/\/\.(?=\w+($|\?))/, '.');
482          // replace escaped `/\.` with `/.`
483          config.url = protocolAndDomain + url.replace(/\/\\\./, '/.');
484
485
486          // set params - delegate param encoding to $http
487          forEach(params, function(value, key) {
488            if (!self.urlParams[key]) {
489              config.params = config.params || {};
490              config.params[key] = value;
491            }
492          });
493        }
494      };
495
496
497      function resourceFactory(url, paramDefaults, actions, options) {
498        var route = new Route(url, options);
499
500        actions = extend({}, provider.defaults.actions, actions);
501
502        function extractParams(data, actionParams) {
503          var ids = {};
504          actionParams = extend({}, paramDefaults, actionParams);
505          forEach(actionParams, function(value, key) {
506            if (isFunction(value)) { value = value(); }
507            ids[key] = value && value.charAt && value.charAt(0) == '@' ?
508              lookupDottedPath(data, value.substr(1)) : value;
509          });
510          return ids;
511        }
512
513        function defaultResponseInterceptor(response) {
514          return response.resource;
515        }
516
517        function Resource(value) {
518          shallowClearAndCopy(value || {}, this);
519        }
520
521        Resource.prototype.toJSON = function() {
522          var data = extend({}, this);
523          delete data.$promise;
524          delete data.$resolved;
525          return data;
526        };
527
528        forEach(actions, function(action, name) {
529          var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
530
531          Resource[name] = function(a1, a2, a3, a4) {
532            var params = {}, data, success, error;
533
534            /* jshint -W086 */ /* (purposefully fall through case statements) */
535            switch (arguments.length) {
536              case 4:
537                error = a4;
538                success = a3;
539              //fallthrough
540              case 3:
541              case 2:
542                if (isFunction(a2)) {
543                  if (isFunction(a1)) {
544                    success = a1;
545                    error = a2;
546                    break;
547                  }
548
549                  success = a2;
550                  error = a3;
551                  //fallthrough
552                } else {
553                  params = a1;
554                  data = a2;
555                  success = a3;
556                  break;
557                }
558              case 1:
559                if (isFunction(a1)) success = a1;
560                else if (hasBody) data = a1;
561                else params = a1;
562                break;
563              case 0: break;
564              default:
565                throw $resourceMinErr('badargs',
566                  "Expected up to 4 arguments [params, data, success, error], got {0} arguments",
567                  arguments.length);
568            }
569            /* jshint +W086 */ /* (purposefully fall through case statements) */
570
571            var isInstanceCall = this instanceof Resource;
572            var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
573            var httpConfig = {};
574            var responseInterceptor = action.interceptor && action.interceptor.response ||
575              defaultResponseInterceptor;
576            var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
577              undefined;
578
579            forEach(action, function(value, key) {
580              switch (key) {
581                default:
582                  httpConfig[key] = copy(value);
583                  break;
584                case 'params':
585                case 'isArray':
586                case 'interceptor':
587                  break;
588                case 'timeout':
589                  if (value && !angular.isNumber(value)) {
590                    $log.debug('ngResource:\n' +
591                        '  Only numeric values are allowed as `timeout`.\n' +
592                        '  Promises are not supported in $resource, because the same value would ' +
593                        'be used for multiple requests.\n' +
594                        '  If you need support for cancellable $resource actions, you should ' +
595                        'upgrade to version 1.5 or higher.');
596                  }
597                  break;
598              }
599            });
600
601            if (hasBody) httpConfig.data = data;
602            route.setUrlParams(httpConfig,
603              extend({}, extractParams(data, action.params || {}), params),
604              action.url);
605
606            var promise = $http(httpConfig).then(function(response) {
607              var data = response.data,
608                promise = value.$promise;
609
610              if (data) {
611                // Need to convert action.isArray to boolean in case it is undefined
612                // jshint -W018
613                if (angular.isArray(data) !== (!!action.isArray)) {
614                  throw $resourceMinErr('badcfg',
615                      'Error in resource configuration for action `{0}`. Expected response to ' +
616                      'contain an {1} but got an {2} (Request: {3} {4})', name, action.isArray ? 'array' : 'object',
617                    angular.isArray(data) ? 'array' : 'object', httpConfig.method, httpConfig.url);
618                }
619                // jshint +W018
620                if (action.isArray) {
621                  value.length = 0;
622                  forEach(data, function(item) {
623                    if (typeof item === "object") {
624                      value.push(new Resource(item));
625                    } else {
626                      // Valid JSON values may be string literals, and these should not be converted
627                      // into objects. These items will not have access to the Resource prototype
628                      // methods, but unfortunately there
629                      value.push(item);
630                    }
631                  });
632                } else {
633                  shallowClearAndCopy(data, value);
634                  value.$promise = promise;
635                }
636              }
637
638              value.$resolved = true;
639
640              response.resource = value;
641
642              return response;
643            }, function(response) {
644              value.$resolved = true;
645
646              (error || noop)(response);
647
648              return $q.reject(response);
649            });
650
651            promise = promise.then(
652              function(response) {
653                var value = responseInterceptor(response);
654                (success || noop)(value, response.headers);
655                return value;
656              },
657              responseErrorInterceptor);
658
659            if (!isInstanceCall) {
660              // we are creating instance / collection
661              // - set the initial promise
662              // - return the instance / collection
663              value.$promise = promise;
664              value.$resolved = false;
665
666              return value;
667            }
668
669            // instance call
670            return promise;
671          };
672
673
674          Resource.prototype['$' + name] = function(params, success, error) {
675            if (isFunction(params)) {
676              error = success; success = params; params = {};
677            }
678            var result = Resource[name].call(this, params, this, success, error);
679            return result.$promise || result;
680          };
681        });
682
683        Resource.bind = function(additionalParamDefaults) {
684          return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
685        };
686
687        return Resource;
688      }
689
690      return resourceFactory;
691    }];
692  });
693
694
695})(window, window.angular);
696
697},{}],2:[function(require,module,exports){
698require('./angular-resource');
699module.exports = 'ngResource';
700
701},{"./angular-resource":1}],3:[function(require,module,exports){
702/**
703 * @license AngularJS v1.5.8
704 * (c) 2010-2016 Google, Inc. http://angularjs.org
705 * License: MIT
706 */
707(function(window, angular) {'use strict';
708
709/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
710 *     Any commits to this file should be reviewed with security in mind.  *
711 *   Changes to this file can potentially create security vulnerabilities. *
712 *          An approval from 2 Core members with history of modifying      *
713 *                         this file is required.                          *
714 *                                                                         *
715 *  Does the change somehow allow for arbitrary javascript to be executed? *
716 *    Or allows for someone to change the prototype of built-in objects?   *
717 *     Or gives undesired access to variables likes document or window?    *
718 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
719
720var $sanitizeMinErr = angular.$$minErr('$sanitize');
721var bind;
722var extend;
723var forEach;
724var isDefined;
725var lowercase;
726var noop;
727var htmlParser;
728var htmlSanitizeWriter;
729
730/**
731 * @ngdoc module
732 * @name ngSanitize
733 * @description
734 *
735 * # ngSanitize
736 *
737 * The `ngSanitize` module provides functionality to sanitize HTML.
738 *
739 *
740 * <div doc-module-components="ngSanitize"></div>
741 *
742 * See {@link ngSanitize.$sanitize `$sanitize`} for usage.
743 */
744
745/**
746 * @ngdoc service
747 * @name $sanitize
748 * @kind function
749 *
750 * @description
751 *   Sanitizes an html string by stripping all potentially dangerous tokens.
752 *
753 *   The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are
754 *   then serialized back to properly escaped html string. This means that no unsafe input can make
755 *   it into the returned string.
756 *
757 *   The whitelist for URL sanitization of attribute values is configured using the functions
758 *   `aHrefSanitizationWhitelist` and `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider
759 *   `$compileProvider`}.
760 *
761 *   The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}.
762 *
763 * @param {string} html HTML input.
764 * @returns {string} Sanitized HTML.
765 *
766 * @example
767   <example module="sanitizeExample" deps="angular-sanitize.js">
768   <file name="index.html">
769     <script>
770         angular.module('sanitizeExample', ['ngSanitize'])
771           .controller('ExampleController', ['$scope', '$sce', function($scope, $sce) {
772             $scope.snippet =
773               '<p style="color:blue">an html\n' +
774               '<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
775               'snippet</p>';
776             $scope.deliberatelyTrustDangerousSnippet = function() {
777               return $sce.trustAsHtml($scope.snippet);
778             };
779           }]);
780     </script>
781     <div ng-controller="ExampleController">
782        Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
783       <table>
784         <tr>
785           <td>Directive</td>
786           <td>How</td>
787           <td>Source</td>
788           <td>Rendered</td>
789         </tr>
790         <tr id="bind-html-with-sanitize">
791           <td>ng-bind-html</td>
792           <td>Automatically uses $sanitize</td>
793           <td><pre>&lt;div ng-bind-html="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
794           <td><div ng-bind-html="snippet"></div></td>
795         </tr>
796         <tr id="bind-html-with-trust">
797           <td>ng-bind-html</td>
798           <td>Bypass $sanitize by explicitly trusting the dangerous value</td>
799           <td>
800           <pre>&lt;div ng-bind-html="deliberatelyTrustDangerousSnippet()"&gt;
801&lt;/div&gt;</pre>
802           </td>
803           <td><div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div></td>
804         </tr>
805         <tr id="bind-default">
806           <td>ng-bind</td>
807           <td>Automatically escapes</td>
808           <td><pre>&lt;div ng-bind="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
809           <td><div ng-bind="snippet"></div></td>
810         </tr>
811       </table>
812       </div>
813   </file>
814   <file name="protractor.js" type="protractor">
815     it('should sanitize the html snippet by default', function() {
816       expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
817         toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
818     });
819
820     it('should inline raw snippet if bound to a trusted value', function() {
821       expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).
822         toBe("<p style=\"color:blue\">an html\n" +
823              "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
824              "snippet</p>");
825     });
826
827     it('should escape snippet without any filter', function() {
828       expect(element(by.css('#bind-default div')).getInnerHtml()).
829         toBe("&lt;p style=\"color:blue\"&gt;an html\n" +
830              "&lt;em onmouseover=\"this.textContent='PWN3D!'\"&gt;click here&lt;/em&gt;\n" +
831              "snippet&lt;/p&gt;");
832     });
833
834     it('should update', function() {
835       element(by.model('snippet')).clear();
836       element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>');
837       expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
838         toBe('new <b>text</b>');
839       expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe(
840         'new <b onclick="alert(1)">text</b>');
841       expect(element(by.css('#bind-default div')).getInnerHtml()).toBe(
842         "new &lt;b onclick=\"alert(1)\"&gt;text&lt;/b&gt;");
843     });
844   </file>
845   </example>
846 */
847
848
849/**
850 * @ngdoc provider
851 * @name $sanitizeProvider
852 *
853 * @description
854 * Creates and configures {@link $sanitize} instance.
855 */
856function $SanitizeProvider() {
857  var svgEnabled = false;
858
859  this.$get = ['$$sanitizeUri', function($$sanitizeUri) {
860    if (svgEnabled) {
861      extend(validElements, svgElements);
862    }
863    return function(html) {
864      var buf = [];
865      htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) {
866        return !/^unsafe:/.test($$sanitizeUri(uri, isImage));
867      }));
868      return buf.join('');
869    };
870  }];
871
872
873  /**
874   * @ngdoc method
875   * @name $sanitizeProvider#enableSvg
876   * @kind function
877   *
878   * @description
879   * Enables a subset of svg to be supported by the sanitizer.
880   *
881   * <div class="alert alert-warning">
882   *   <p>By enabling this setting without taking other precautions, you might expose your
883   *   application to click-hijacking attacks. In these attacks, sanitized svg elements could be positioned
884   *   outside of the containing element and be rendered over other elements on the page (e.g. a login
885   *   link). Such behavior can then result in phishing incidents.</p>
886   *
887   *   <p>To protect against these, explicitly setup `overflow: hidden` css rule for all potential svg
888   *   tags within the sanitized content:</p>
889   *
890   *   <br>
891   *
892   *   <pre><code>
893   *   .rootOfTheIncludedContent svg {
894   *     overflow: hidden !important;
895   *   }
896   *   </code></pre>
897   * </div>
898   *
899   * @param {boolean=} flag Enable or disable SVG support in the sanitizer.
900   * @returns {boolean|ng.$sanitizeProvider} Returns the currently configured value if called
901   *    without an argument or self for chaining otherwise.
902   */
903  this.enableSvg = function(enableSvg) {
904    if (isDefined(enableSvg)) {
905      svgEnabled = enableSvg;
906      return this;
907    } else {
908      return svgEnabled;
909    }
910  };
911
912  //////////////////////////////////////////////////////////////////////////////////////////////////
913  // Private stuff
914  //////////////////////////////////////////////////////////////////////////////////////////////////
915
916  bind = angular.bind;
917  extend = angular.extend;
918  forEach = angular.forEach;
919  isDefined = angular.isDefined;
920  lowercase = angular.lowercase;
921  noop = angular.noop;
922
923  htmlParser = htmlParserImpl;
924  htmlSanitizeWriter = htmlSanitizeWriterImpl;
925
926  // Regular Expressions for parsing tags and attributes
927  var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
928    // Match everything outside of normal chars and " (quote character)
929    NON_ALPHANUMERIC_REGEXP = /([^\#-~ |!])/g;
930
931
932  // Good source of info about elements and attributes
933  // http://dev.w3.org/html5/spec/Overview.html#semantics
934  // http://simon.html5.org/html-elements
935
936  // Safe Void Elements - HTML5
937  // http://dev.w3.org/html5/spec/Overview.html#void-elements
938  var voidElements = toMap("area,br,col,hr,img,wbr");
939
940  // Elements that you can, intentionally, leave open (and which close themselves)
941  // http://dev.w3.org/html5/spec/Overview.html#optional-tags
942  var optionalEndTagBlockElements = toMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
943      optionalEndTagInlineElements = toMap("rp,rt"),
944      optionalEndTagElements = extend({},
945                                              optionalEndTagInlineElements,
946                                              optionalEndTagBlockElements);
947
948  // Safe Block Elements - HTML5
949  var blockElements = extend({}, optionalEndTagBlockElements, toMap("address,article," +
950          "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," +
951          "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul"));
952
953  // Inline Elements - HTML5
954  var inlineElements = extend({}, optionalEndTagInlineElements, toMap("a,abbr,acronym,b," +
955          "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," +
956          "samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
957
958  // SVG Elements
959  // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements
960  // Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted.
961  // They can potentially allow for arbitrary javascript to be executed. See #11290
962  var svgElements = toMap("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph," +
963          "hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline," +
964          "radialGradient,rect,stop,svg,switch,text,title,tspan");
965
966  // Blocked Elements (will be stripped)
967  var blockedElements = toMap("script,style");
968
969  var validElements = extend({},
970                                     voidElements,
971                                     blockElements,
972                                     inlineElements,
973                                     optionalEndTagElements);
974
975  //Attributes that have href and hence need to be sanitized
976  var uriAttrs = toMap("background,cite,href,longdesc,src,xlink:href");
977
978  var htmlAttrs = toMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' +
979      'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' +
980      'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' +
981      'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' +
982      'valign,value,vspace,width');
983
984  // SVG attributes (without "id" and "name" attributes)
985  // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes
986  var svgAttrs = toMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' +
987      'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' +
988      'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' +
989      'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' +
990      'height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,' +
991      'marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,' +
992      'max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,' +
993      'path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,' +
994      'requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,' +
995      'stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,' +
996      'stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,' +
997      'stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,' +
998      'underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,' +
999      'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,' +
1000      'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan', true);
1001
1002  var validAttrs = extend({},
1003                                  uriAttrs,
1004                                  svgAttrs,
1005                                  htmlAttrs);
1006
1007  function toMap(str, lowercaseKeys) {
1008    var obj = {}, items = str.split(','), i;
1009    for (i = 0; i < items.length; i++) {
1010      obj[lowercaseKeys ? lowercase(items[i]) : items[i]] = true;
1011    }
1012    return obj;
1013  }
1014
1015  var inertBodyElement;
1016  (function(window) {
1017    var doc;
1018    if (window.document && window.document.implementation) {
1019      doc = window.document.implementation.createHTMLDocument("inert");
1020    } else {
1021      throw $sanitizeMinErr('noinert', "Can't create an inert html document");
1022    }
1023    var docElement = doc.documentElement || doc.getDocumentElement();
1024    var bodyElements = docElement.getElementsByTagName('body');
1025
1026    // usually there should be only one body element in the document, but IE doesn't have any, so we need to create one
1027    if (bodyElements.length === 1) {
1028      inertBodyElement = bodyElements[0];
1029    } else {
1030      var html = doc.createElement('html');
1031      inertBodyElement = doc.createElement('body');
1032      html.appendChild(inertBodyElement);
1033      doc.appendChild(html);
1034    }
1035  })(window);
1036
1037  /**
1038   * @example
1039   * htmlParser(htmlString, {
1040   *     start: function(tag, attrs) {},
1041   *     end: function(tag) {},
1042   *     chars: function(text) {},
1043   *     comment: function(text) {}
1044   * });
1045   *
1046   * @param {string} html string
1047   * @param {object} handler
1048   */
1049  function htmlParserImpl(html, handler) {
1050    if (html === null || html === undefined) {
1051      html = '';
1052    } else if (typeof html !== 'string') {
1053      html = '' + html;
1054    }
1055    inertBodyElement.innerHTML = html;
1056
1057    //mXSS protection
1058    var mXSSAttempts = 5;
1059    do {
1060      if (mXSSAttempts === 0) {
1061        throw $sanitizeMinErr('uinput', "Failed to sanitize html because the input is unstable");
1062      }
1063      mXSSAttempts--;
1064
1065      // strip custom-namespaced attributes on IE<=11
1066      if (window.document.documentMode) {
1067        stripCustomNsAttrs(inertBodyElement);
1068      }
1069      html = inertBodyElement.innerHTML; //trigger mXSS
1070      inertBodyElement.innerHTML = html;
1071    } while (html !== inertBodyElement.innerHTML);
1072
1073    var node = inertBodyElement.firstChild;
1074    while (node) {
1075      switch (node.nodeType) {
1076        case 1: // ELEMENT_NODE
1077          handler.start(node.nodeName.toLowerCase(), attrToMap(node.attributes));
1078          break;
1079        case 3: // TEXT NODE
1080          handler.chars(node.textContent);
1081          break;
1082      }
1083
1084      var nextNode;
1085      if (!(nextNode = node.firstChild)) {
1086      if (node.nodeType == 1) {
1087          handler.end(node.nodeName.toLowerCase());
1088        }
1089        nextNode = node.nextSibling;
1090        if (!nextNode) {
1091          while (nextNode == null) {
1092            node = node.parentNode;
1093            if (node === inertBodyElement) break;
1094            nextNode = node.nextSibling;
1095          if (node.nodeType == 1) {
1096              handler.end(node.nodeName.toLowerCase());
1097            }
1098          }
1099        }
1100      }
1101      node = nextNode;
1102    }
1103
1104    while (node = inertBodyElement.firstChild) {
1105      inertBodyElement.removeChild(node);
1106    }
1107  }
1108
1109  function attrToMap(attrs) {
1110    var map = {};
1111    for (var i = 0, ii = attrs.length; i < ii; i++) {
1112      var attr = attrs[i];
1113      map[attr.name] = attr.value;
1114    }
1115    return map;
1116  }
1117
1118
1119  /**
1120   * Escapes all potentially dangerous characters, so that the
1121   * resulting string can be safely inserted into attribute or
1122   * element text.
1123   * @param value
1124   * @returns {string} escaped text
1125   */
1126  function encodeEntities(value) {
1127    return value.
1128      replace(/&/g, '&amp;').
1129      replace(SURROGATE_PAIR_REGEXP, function(value) {
1130        var hi = value.charCodeAt(0);
1131        var low = value.charCodeAt(1);
1132        return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
1133      }).
1134      replace(NON_ALPHANUMERIC_REGEXP, function(value) {
1135        return '&#' + value.charCodeAt(0) + ';';
1136      }).
1137      replace(/</g, '&lt;').
1138      replace(/>/g, '&gt;');
1139  }
1140
1141  /**
1142   * create an HTML/XML writer which writes to buffer
1143   * @param {Array} buf use buf.join('') to get out sanitized html string
1144   * @returns {object} in the form of {
1145   *     start: function(tag, attrs) {},
1146   *     end: function(tag) {},
1147   *     chars: function(text) {},
1148   *     comment: function(text) {}
1149   * }
1150   */
1151  function htmlSanitizeWriterImpl(buf, uriValidator) {
1152    var ignoreCurrentElement = false;
vendor: 3,620 bytes, lines 1153-1273
1153    var out = bind(buf, buf.push);
1154    return {
1155      start: function(tag, attrs) {
1156        tag = lowercase(tag);
1157        if (!ignoreCurrentElement && blockedElements[tag]) {
1158          ignoreCurrentElement = tag;
1159        }
1160        if (!ignoreCurrentElement && validElements[tag] === true) {
1161          out('<');
1162          out(tag);
1163          forEach(attrs, function(value, key) {
1164            var lkey = lowercase(key);
1165            var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background');
1166            if (validAttrs[lkey] === true &&
1167              (uriAttrs[lkey] !== true || uriValidator(value, isImage))) {
1168              out(' ');
1169              out(key);
1170              out('="');
1171              out(encodeEntities(value));
1172              out('"');
1173            }
1174          });
1175          out('>');
1176        }
1177      },
1178      end: function(tag) {
1179        tag = lowercase(tag);
1180        if (!ignoreCurrentElement && validElements[tag] === true && voidElements[tag] !== true) {
1181          out('</');
1182          out(tag);
1183          out('>');
1184        }
1185        if (tag == ignoreCurrentElement) {
1186          ignoreCurrentElement = false;
1187        }
1188      },
1189      chars: function(chars) {
1190        if (!ignoreCurrentElement) {
1191          out(encodeEntities(chars));
1192        }
1193      }
1194    };
1195  }
1196
1197
1198  /**
1199   * When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1' attribute to declare
1200   * ns1 namespace and prefixes the attribute with 'ns1' (e.g. 'ns1:xlink:foo'). This is undesirable since we don't want
1201   * to allow any of these custom attributes. This method strips them all.
1202   *
1203   * @param node Root element to process
1204   */
1205  function stripCustomNsAttrs(node) {
1206    if (node.nodeType === window.Node.ELEMENT_NODE) {
1207      var attrs = node.attributes;
1208      for (var i = 0, l = attrs.length; i < l; i++) {
1209        var attrNode = attrs[i];
1210        var attrName = attrNode.name.toLowerCase();
1211        if (attrName === 'xmlns:ns1' || attrName.lastIndexOf('ns1:', 0) === 0) {
1212          node.removeAttributeNode(attrNode);
1213          i--;
1214          l--;
1215        }
1216      }
1217    }
1218
1219    var nextNode = node.firstChild;
1220    if (nextNode) {
1221      stripCustomNsAttrs(nextNode);
1222    }
1223
1224    nextNode = node.nextSibling;
1225    if (nextNode) {
1226      stripCustomNsAttrs(nextNode);
1227    }
1228  }
1229}
1230
1231function sanitizeText(chars) {
1232  var buf = [];
1233  var writer = htmlSanitizeWriter(buf, noop);
1234  writer.chars(chars);
1235  return buf.join('');
1236}
1237
1238
1239// define ngSanitize module and register $sanitize service
1240angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
1241
1242/**
1243 * @ngdoc filter
1244 * @name linky
1245 * @kind function
1246 *
1247 * @description
1248 * Finds links in text input and turns them into html links. Supports `http/https/ftp/mailto` and
1249 * plain email address links.
1250 *
1251 * Requires the {@link ngSanitize `ngSanitize`} module to be installed.
1252 *
1253 * @param {string} text Input text.
1254 * @param {string} target Window (`_blank|_self|_parent|_top`) or named frame to open links in.
1255 * @param {object|function(url)} [attributes] Add custom attributes to the link element.
1256 *
1257 *    Can be one of:
1258 *
1259 *    - `object`: A map of attributes
1260 *    - `function`: Takes the url as a parameter and returns a map of attributes
1261 *
1262 *    If the map of attributes contains a value for `target`, it overrides the value of
1263 *    the target parameter.
1264 *
1265 *
1266 * @returns {string} Html-linkified and {@link $sanitize sanitized} text.
1267 *
1268 * @usage
1269   <span ng-bind-html="linky_expression | linky"></span>
1270 *
1271 * @example
1272   <example module="linkyExample" deps="angular-sanitize.js">
1273     <file name="index.html">
1274       <div ng-controller="ExampleController">
1275       Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
1276       <table>
1277         <tr>
1278           <th>Filter</th>
1279           <th>Source</th>
1280           <th>Rendered</th>
1281         </tr>
1282         <tr id="linky-filter">
1283           <td>linky filter</td>
1284           <td>
1285             <pre>&lt;div ng-bind-html="snippet | linky"&gt;<br>&lt;/div&gt;</pre>
1286           </td>
1287           <td>
1288             <div ng-bind-html="snippet | linky"></div>
1289           </td>
1290         </tr>
1291         <tr id="linky-target">
1292          <td>linky target</td>
1293          <td>
1294            <pre>&lt;div ng-bind-html="snippetWithSingleURL | linky:'_blank'"&gt;<br>&lt;/div&gt;</pre>
1295          </td>
1296          <td>
1297            <div ng-bind-html="snippetWithSingleURL | linky:'_blank'"></div>
1298          </td>
1299         </tr>
1300         <tr id="linky-custom-attributes">
1301          <td>linky custom attributes</td>
1302          <td>
1303            <pre>&lt;div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}"&gt;<br>&lt;/div&gt;</pre>
1304          </td>
1305          <td>
1306            <div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}"></div>
1307          </td>
1308         </tr>
1309         <tr id="escaped-html">
1310           <td>no filter</td>
1311           <td><pre>&lt;div ng-bind="snippet"&gt;<br>&lt;/div&gt;</pre></td>
1312           <td><div ng-bind="snippet"></div></td>
1313         </tr>
1314       </table>
1315     </file>
1316     <file name="script.js">
1317       angular.module('linkyExample', ['ngSanitize'])
1318         .controller('ExampleController', ['$scope', function($scope) {
1319           $scope.snippet =
1320             'Pretty text with some links:\n'+
1321             'http://angularjs.org/,\n'+
1322             'mailto:[email protected],\n'+
1323             '[email protected],\n'+
1324             'and one more: ftp://127.0.0.1/.';
1325           $scope.snippetWithSingleURL = 'http://angularjs.org/';
1326         }]);
1327     </file>
1328     <file name="protractor.js" type="protractor">
1329       it('should linkify the snippet with urls', function() {
1330         expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
1331             toBe('Pretty text with some links: http://angularjs.org/, [email protected], ' +
1332                  '[email protected], and one more: ftp://127.0.0.1/.');
1333         expect(element.all(by.css('#linky-filter a')).count()).toEqual(4);
1334       });
1335
1336       it('should not linkify snippet without the linky filter', function() {
1337         expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()).
1338             toBe('Pretty text with some links: http://angularjs.org/, mailto:[email protected], ' +
1339                  '[email protected], and one more: ftp://127.0.0.1/.');
1340         expect(element.all(by.css('#escaped-html a')).count()).toEqual(0);
1341       });
1342
1343       it('should update', function() {
1344         element(by.model('snippet')).clear();
1345         element(by.model('snippet')).sendKeys('new http://link.');
1346         expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
1347             toBe('new http://link.');
1348         expect(element.all(by.css('#linky-filter a')).count()).toEqual(1);
1349         expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText())
1350             .toBe('new http://link.');
1351       });
1352
1353       it('should work with the target property', function() {
1354        expect(element(by.id('linky-target')).
1355            element(by.binding("snippetWithSingleURL | linky:'_blank'")).getText()).
1356            toBe('http://angularjs.org/');
1357        expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
1358       });
1359
1360       it('should optionally add custom attributes', function() {
1361        expect(element(by.id('linky-custom-attributes')).
1362            element(by.binding("snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}")).getText()).
1363            toBe('http://angularjs.org/');
1364        expect(element(by.css('#linky-custom-attributes a')).getAttribute('rel')).toEqual('nofollow');
1365       });
1366     </file>
1367   </example>
1368 */
1369angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
1370  var LINKY_URL_REGEXP =
1371        /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
1372      MAILTO_REGEXP = /^mailto:/i;
1373
1374  var linkyMinErr = angular.$$minErr('linky');
1375  var isDefined = angular.isDefined;
1376  var isFunction = angular.isFunction;
1377  var isObject = angular.isObject;
1378  var isString = angular.isString;
1379
1380  return function(text, target, attributes) {
1381    if (text == null || text === '') return text;
1382    if (!isString(text)) throw linkyMinErr('notstring', 'Expected string but received: {0}', text);
1383
1384    var attributesFn =
1385      isFunction(attributes) ? attributes :
1386      isObject(attributes) ? function getAttributesObject() {return attributes;} :
1387      function getEmptyAttributesObject() {return {};};
1388
1389    var match;
1390    var raw = text;
1391    var html = [];
1392    var url;
1393    var i;
1394    while ((match = raw.match(LINKY_URL_REGEXP))) {
1395      // We can not end in these as they are sometimes found at the end of the sentence
1396      url = match[0];
1397      // if we did not match ftp/http/www/mailto then assume mailto
1398      if (!match[2] && !match[4]) {
1399        url = (match[3] ? 'http://' : 'mailto:') + url;
1400      }
1401      i = match.index;
1402      addText(raw.substr(0, i));
1403      addLink(url, match[0].replace(MAILTO_REGEXP, ''));
1404      raw = raw.substring(i + match[0].length);
1405    }
1406    addText(raw);
1407    return $sanitize(html.join(''));
1408
1409    function addText(text) {
1410      if (!text) {
1411        return;
1412      }
1413      html.push(sanitizeText(text));
1414    }
1415
1416    function addLink(url, text) {
1417      var key, linkAttributes = attributesFn(url);
1418      html.push('<a ');
1419
1420      for (key in linkAttributes) {
1421        html.push(key + '="' + linkAttributes[key] + '" ');
1422      }
1423
1424      if (isDefined(target) && !('target' in linkAttributes)) {
1425        html.push('target="',
1426                  target,
1427                  '" ');
1428      }
1429      html.push('href="',
1430                url.replace(/"/g, '&quot;'),
1431                '">');
1432      addText(text);
1433      html.push('</a>');
1434    }
1435  };
1436}]);
1437
1438
1439})(window, window.angular);
1440
1441},{}],4:[function(require,module,exports){
1442require('./angular-sanitize');
1443module.exports = 'ngSanitize';
1444
1445},{"./angular-sanitize":3}],5:[function(require,module,exports){
1446'use strict';
1447
1448var keys = require('object-keys');
1449var foreach = require('foreach');
1450var hasSymbols = typeof Symbol === 'function' && typeof Symbol() === 'symbol';
1451
1452var toStr = Object.prototype.toString;
1453
1454var isFunction = function (fn) {
1455	return typeof fn === 'function' && toStr.call(fn) === '[object Function]';
1456};
1457
1458var arePropertyDescriptorsSupported = function () {
1459	var obj = {};
1460	try {
1461		Object.defineProperty(obj, 'x', { enumerable: false, value: obj });
1462        /* eslint-disable no-unused-vars, no-restricted-syntax */
1463        for (var _ in obj) { return false; }
1464        /* eslint-enable no-unused-vars, no-restricted-syntax */
1465		return obj.x === obj;
1466	} catch (e) { /* this is IE 8. */
1467		return false;
1468	}
1469};
1470var supportsDescriptors = Object.defineProperty && arePropertyDescriptorsSupported();
1471
1472var defineProperty = function (object, name, value, predicate) {
1473	if (name in object && (!isFunction(predicate) || !predicate())) {
1474		return;
1475	}
1476	if (supportsDescriptors) {
1477		Object.defineProperty(object, name, {
1478			configurable: true,
1479			enumerable: false,
1480			value: value,
1481			writable: true
1482		});
1483	} else {
1484		object[name] = value;
1485	}
1486};
1487
1488var defineProperties = function (object, map) {
1489	var predicates = arguments.length > 2 ? arguments[2] : {};
1490	var props = keys(map);
1491	if (hasSymbols) {
1492		props = props.concat(Object.getOwnPropertySymbols(map));
1493	}
1494	foreach(props, function (name) {
1495		defineProperty(object, name, map[name], predicates[name]);
1496	});
1497};
1498
1499defineProperties.supportsDescriptors = !!supportsDescriptors;
1500
1501module.exports = defineProperties;
1502
1503},{"foreach":6,"object-keys":10}],6:[function(require,module,exports){
1504
1505var hasOwn = Object.prototype.hasOwnProperty;
1506var toString = Object.prototype.toString;
1507
1508module.exports = function forEach (obj, fn, ctx) {
1509    if (toString.call(fn) !== '[object Function]') {
1510        throw new TypeError('iterator must be a function');
1511    }
1512    var l = obj.length;
1513    if (l === +l) {
1514        for (var i = 0; i < l; i++) {
1515            fn.call(ctx, obj[i], i, obj);
1516        }
1517    } else {
1518        for (var k in obj) {
1519            if (hasOwn.call(obj, k)) {
1520                fn.call(ctx, obj[k], k, obj);
1521            }
1522        }
1523    }
1524};
1525
1526
1527},{}],7:[function(require,module,exports){
1528'use strict';
1529
1530var assign = Object.assign || require('object.assign');
1531
1532module.exports = function toArraySubClassFactory(ArraySubClass) {
1533  ArraySubClass.prototype = assign(Object.create(Array.prototype),  ArraySubClass.prototype);
1534
1535  return function () {
1536    var arr = [ ];
1537    arr.__proto__ = ArraySubClass.prototype; // jshint ignore:line
1538
1539    ArraySubClass.apply(arr, arguments);
1540
1541    return arr;
1542  };
1543};
1544
1545
1546},{"object.assign":13}],8:[function(require,module,exports){
1547'use strict';
1548
1549angular.module('ngMasonry', [])
1550    .controller('masonryController', function () {
1551        var vm = this;
1552
1553        vm.config = {};
1554        vm.container = undefined;
1555        vm.ready = ready;
1556        vm.initialize = initialize;
1557        vm.reLayout = reLayout;
1558
1559        function ready() {
1560            return !!vm.config && !!vm.config.masonryContainer;
1561        }
1562
1563        function initialize() {
1564            var defaultOpts = {itemSelector: vm.config.masonryItem},
1565                opts = !vm.config.masonryOption ? defaultOpts : angular.extend(defaultOpts, vm.config.masonryOption);
1566
1567            vm.container = new Masonry(vm.config.masonryContainer, opts);
1568
1569            if (typeof imagesLoaded !== 'undefined') {
1570                new imagesLoaded(vm.config.masonryContainer, function () {
1571                    vm.reLayout();
1572                });
1573            }
1574        }
1575
1576        function reLayout() {
1577            vm.container.layout();
1578        }
1579    })
1580    .directive('masonry', function () {
1581        var directive = {
1582            restrict: 'A',
1583            controller: 'masonryController',
1584            compile: compile
1585        };
1586
1587        return directive;
1588
1589        function compile(element, attributes) {
1590            var flag = false,
1591                child = angular.element(document.querySelectorAll('[' + attributes.$attr.masonry + '] [data-masonry-item], [' + attributes.$attr.masonry + '] [masonry-item]'));
1592
1593            angular.forEach(child, function (obj) {
1594                obj = angular.element(obj);
1595                if (obj.attr('ng-repeat') !== undefined || obj.attr('data-ng-repeat') !== undefined) {
1596                    flag = true;
1597                    obj.attr('data-masonry-after-render', '');
1598                }
1599            });
1600            return {
1601                pre: function (scope, element, attributes, controller) {
1602                    controller.config.masonryContainer = '[' + attributes.$attr.masonry + ']';
1603                    controller.config.masonryOptions = JSON.parse(attributes.masonryOptions || '{}');
1604                },
1605                post: function (scope, element, attributes, controller) {
1606                    if (!flag) {
1607                        controller.initialize();
1608                    }
1609                }
1610            };
1611        }
1612    })
1613    .directive('masonryItem', function () {
1614        var directive = {
1615            restrict: 'A',
1616            require: '^masonry',
1617            priority: 1,
1618            compile: compile
1619        };
1620
1621        return directive;
1622
1623        function compile() {
1624            return {
1625                pre: function (scope, element, attributes, controller) {
1626                    if (controller.config.masonryItem === undefined) {
1627                        controller.config.masonryItem = '[' + attributes.$attr.masonryItem + ']';
1628                    }
1629                }
1630            };
1631        }
1632    })
1633    .directive('masonryAfterRender', ["$timeout", function ($timeout) {
1634        'ngInject';
1635        var directive = {
1636            restrict: 'A',
1637            require: '^masonry',
1638            priority: 0,
1639            link: link
1640        };
1641
1642        return directive;
1643
1644        function link(scope, element, attr, controller) {
1645            if (scope.$last) {
1646                var timeout = null;
1647                timeout = $timeout(function () {
1648                    controller.initialize();
1649                    $timeout.cancel(timeout);
1650                });
1651            }
1652        }
1653    }]);
1654},{}],9:[function(require,module,exports){
1655require('./angular-masonry');
1656module.exports = 'ngMasonry';
1657},{"./angular-masonry":8}],10:[function(require,module,exports){
1658'use strict';
1659
1660// modified from https://github.com/es-shims/es5-shim
1661var has = Object.prototype.hasOwnProperty;
1662var toStr = Object.prototype.toString;
1663var slice = Array.prototype.slice;
1664var isArgs = require('./isArguments');
1665var isEnumerable = Object.prototype.propertyIsEnumerable;
1666var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString');
1667var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype');
1668var dontEnums = [
1669	'toString',
1670	'toLocaleString',
1671	'valueOf',
1672	'hasOwnProperty',
1673	'isPrototypeOf',
1674	'propertyIsEnumerable',
1675	'constructor'
1676];
1677var equalsConstructorPrototype = function (o) {
1678	var ctor = o.constructor;
1679	return ctor && ctor.prototype === o;
1680};
1681var excludedKeys = {
1682	$console: true,
1683	$external: true,
1684	$frame: true,
1685	$frameElement: true,
1686	$frames: true,
1687	$innerHeight: true,
1688	$innerWidth: true,
1689	$outerHeight: true,
1690	$outerWidth: true,
1691	$pageXOffset: true,
1692	$pageYOffset: true,
1693	$parent: true,
1694	$scrollLeft: true,
1695	$scrollTop: true,
1696	$scrollX: true,
1697	$scrollY: true,
1698	$self: true,
1699	$webkitIndexedDB: true,
1700	$webkitStorageInfo: true,
1701	$window: true
1702};
1703var hasAutomationEqualityBug = (function () {
1704	/* global window */
1705	if (typeof window === 'undefined') { return false; }
1706	for (var k in window) {
1707		try {
1708			if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') {
1709				try {
1710					equalsConstructorPrototype(window[k]);
1711				} catch (e) {
1712					return true;
1713				}
1714			}
1715		} catch (e) {
1716			return true;
1717		}
1718	}
1719	return false;
1720}());
1721var equalsConstructorPrototypeIfNotBuggy = function (o) {
1722	/* global window */
1723	if (typeof window === 'undefined' || !hasAutomationEqualityBug) {
1724		return equalsConstructorPrototype(o);
1725	}
1726	try {
1727		return equalsConstructorPrototype(o);
1728	} catch (e) {
1729		return false;
1730	}
1731};
1732
1733var keysShim = function keys(object) {
1734	var isObject = object !== null && typeof object === 'object';
1735	var isFunction = toStr.call(object) === '[object Function]';
1736	var isArguments = isArgs(object);
1737	var isString = isObject && toStr.call(object) === '[object String]';
1738	var theKeys = [];
1739
1740	if (!isObject && !isFunction && !isArguments) {
1741		throw new TypeError('Object.keys called on a non-object');
1742	}
1743
1744	var skipProto = hasProtoEnumBug && isFunction;
1745	if (isString && object.length > 0 && !has.call(object, 0)) {
1746		for (var i = 0; i < object.length; ++i) {
1747			theKeys.push(String(i));
1748		}
1749	}
1750
1751	if (isArguments && object.length > 0) {
1752		for (var j = 0; j < object.length; ++j) {
1753			theKeys.push(String(j));
1754		}
1755	} else {
1756		for (var name in object) {
1757			if (!(skipProto && name === 'prototype') && has.call(object, name)) {
1758				theKeys.push(String(name));
1759			}
1760		}
1761	}
1762
1763	if (hasDontEnumBug) {
1764		var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object);
1765
1766		for (var k = 0; k < dontEnums.length; ++k) {
1767			if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) {
1768				theKeys.push(dontEnums[k]);
1769			}
1770		}
1771	}
1772	return theKeys;
1773};
1774
1775keysShim.shim = function shimObjectKeys() {
1776	if (Object.keys) {
1777		var keysWorksWithArguments = (function () {
1778			// Safari 5.0 bug
1779			return (Object.keys(arguments) || '').length === 2;
1780		}(1, 2));
1781		if (!keysWorksWithArguments) {
1782			var originalKeys = Object.keys;
1783			Object.keys = function keys(object) {
1784				if (isArgs(object)) {
1785					return originalKeys(slice.call(object));
1786				} else {
1787					return originalKeys(object);
1788				}
1789			};
1790		}
1791	} else {
1792		Object.keys = keysShim;
1793	}
1794	return Object.keys || keysShim;
1795};
1796
1797module.exports = keysShim;
1798
1799},{"./isArguments":11}],11:[function(require,module,exports){
1800'use strict';
1801
1802var toStr = Object.prototype.toString;
1803
1804module.exports = function isArguments(value) {
1805	var str = toStr.call(value);
1806	var isArgs = str === '[object Arguments]';
1807	if (!isArgs) {
1808		isArgs = str !== '[object Array]' &&
1809			value !== null &&
1810			typeof value === 'object' &&
1811			typeof value.length === 'number' &&
1812			value.length >= 0 &&
1813			toStr.call(value.callee) === '[object Function]';
1814	}
1815	return isArgs;
1816};
1817
1818},{}],12:[function(require,module,exports){
1819var keys = require('object-keys');
1820
1821module.exports = function hasSymbols() {
1822	if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; }
1823	if (typeof Symbol.iterator === 'symbol') { return true; }
1824
1825	var obj = {};
1826	var sym = Symbol('test');
1827	if (typeof sym === 'string') { return false; }
1828	if (sym instanceof Symbol) { return false; }
1829	obj[sym] = 42;
1830	for (sym in obj) { return false; }
1831	if (keys(obj).length !== 0) { return false; }
1832	if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; }
1833
1834	if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; }
1835
1836	var syms = Object.getOwnPropertySymbols(obj);
1837	if (syms.length !== 1 || syms[0] !== sym) { return false; }
1838
1839	if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; }
1840
1841	if (typeof Object.getOwnPropertyDescriptor === 'function') {
1842		var descriptor = Object.getOwnPropertyDescriptor(obj, sym);
1843		if (descriptor.value !== 42 || descriptor.enumerable !== true) { return false; }
1844	}
1845
1846	return true;
1847};
1848
1849},{"object-keys":10}],13:[function(require,module,exports){
1850'use strict';
1851
1852// modified from https://github.com/es-shims/es6-shim
1853var keys = require('object-keys');
1854var canBeObject = function (obj) {
1855	return typeof obj !== 'undefined' && obj !== null;
1856};
1857var hasSymbols = require('./hasSymbols')();
1858var defineProperties = require('define-properties');
1859var toObject = Object;
1860var push = Array.prototype.push;
1861var propIsEnumerable = Object.prototype.propertyIsEnumerable;
1862
1863var assignShim = function assign(target, source1) {
1864	if (!canBeObject(target)) { throw new TypeError('target must be an object'); }
1865	var objTarget = toObject(target);
1866	var s, source, i, props, syms;
1867	for (s = 1; s < arguments.length; ++s) {
1868		source = toObject(arguments[s]);
1869		props = keys(source);
1870		if (hasSymbols && Object.getOwnPropertySymbols) {
1871			syms = Object.getOwnPropertySymbols(source);
1872			for (i = 0; i < syms.length; ++i) {
1873				if (propIsEnumerable.call(source, syms[i])) {
1874					push.call(props, syms[i]);
1875				}
1876			}
1877		}
1878		for (i = 0; i < props.length; ++i) {
1879			objTarget[props[i]] = source[props[i]];
1880		}
1881	}
1882	return objTarget;
1883};
1884
1885defineProperties(assignShim, {
1886	shim: function shimObjectAssign() {
1887		var assignHasPendingExceptions = function () {
1888			if (!Object.assign || !Object.preventExtensions) {
1889				return false;
1890			}
1891			// Firefox 37 still has "pending exception" logic in its Object.assign implementation,
1892			// which is 72% slower than our shim, and Firefox 40's native implementation.
1893			var thrower = Object.preventExtensions({ 1: 2 });
1894			try {
1895				Object.assign(thrower, 'xy');
1896			} catch (e) {
1897				return thrower[1] === 'y';
1898			}
1899		};
1900		defineProperties(
1901			Object,
1902			{ assign: assignShim },
1903			{ assign: assignHasPendingExceptions }
1904		);
1905		return Object.assign || assignShim;
1906	}
1907});
1908
1909module.exports = assignShim;
1910
1911},{"./hasSymbols":12,"define-properties":5,"object-keys":10}],14:[function(require,module,exports){
1912require('./app/core/core');
1913require('./app/fos_user/fos_user');
1914require('./app/mountains/mountains');
1915require('./app/token_users/token_users');
1916require('./app/profile/profile');
1917require('./app/search/search');
1918require('./app/events/events');
1919require('./app/club/club');
1920require('./app/page/page');
1921require('./app/news/news');
1922require('./app/index/index');
1923require('./app/discipline/discipline');
1924require('./app/committee/committee');
1925require('./app/competition/competition');
1926require('./app/rank/rank');
1927require('./app/education/education');
1928require('./app/project/project');
1929require('./app/camp/camp');
1930require('./app/subclub/subclub');
1931require('./app/blog/blog.controller');
1932require('./app/insurance/insurance');
1933require('./cropper/cropping');
1934
1935},{"./app/blog/blog.controller":15,"./app/camp/camp":16,"./app/club/club":22,"./app/committee/committee":28,"./app/competition/competition":32,"./app/core/core":38,"./app/discipline/discipline":44,"./app/education/education":53,"./app/events/events":61,"./app/fos_user/fos_user":67,"./app/index/index":70,"./app/insurance/insurance":80,"./app/mountains/mountains":86,"./app/news/news":92,"./app/page/page":95,"./app/profile/profile":104,"./app/project/project":108,"./app/rank/rank":112,"./app/search/search":131,"./app/subclub/subclub":134,"./app/token_users/token_users":137,"./cropper/cropping":139}],15:[function(require,module,exports){
1936/**
1937 * Created by PhpStorm on 29.05.2017.
1938 * Author: Shabalin Pavel
1939 * Email: [email protected]
1940 */
1941'use strict';
1942
1943require('../core/core');
1944require('../../modules/forms/forms');
1945require('../../modules/maps/maps');
1946require('../../modals/slider/slider');
1947require('../../helpers/show-modal-message/show-modal-message');
1948
1949require('../../models/blog/post');
1950
1951angular.module('far.blog', [
1952    'far.core',
1953    'far.models.post',
1954    'far.helpers.showModalMessage',
1955    'far.modals.slider',
1956]);
1957
1958angular.module('far.blog').controller('BlogFrontController', ["Post", "$uibModal", function(Post, $uibModal) {
1959    var vm = {
1960        post: {},
1961        openSlider: openSlider,
1962        init: function(id) {
1963            vm.post = Post.get(id, function() {
1964
1965            });
1966        }
1967    };
1968
1969    function openSlider(slide) {
1970        $uibModal.open({
1971            templateUrl: '/modals/slider/slider.html',
1972            controller: 'SliderController as slider',
1973            resolve: {
1974                slides: function() {
1975                    return vm.post.slides_files;
1976                },
1977                selectedSlide: function() {
1978                    return slide;
1979                }
1980            }
1981        });
1982    }
1983
1984
1985
1986    return vm;
1987}]);
1988
1989},{"../../helpers/show-modal-message/show-modal-message":167,"../../modals/slider/slider":182,"../../models/blog/post":186,"../../modules/forms/forms":244,"../../modules/maps/maps":338,"../core/core":38}],16:[function(require,module,exports){
1990require('./camp.module');
1991require('./controllers/edit.controller');
1992require('./controllers/events.controller');
1993require('./controllers/routes.controller');
1994require('./controllers/description.controller');
1995
1996},{"./camp.module":17,"./controllers/description.controller":18,"./controllers/edit.controller":19,"./controllers/events.controller":20,"./controllers/routes.controller":21}],17:[function(require,module,exports){
1997'use strict';
1998'use strict';
1999
2000require('../core/core');
2001require('../../modules/pagination/pagination');
2002require('../../modules/forms/forms');
2003
2004require('../../models/camp/camp');
2005
2006require('../../forms/inviteUserForm');
2007require('../../forms/themes/inviteUser/inviteUser.theme');
2008
2009require('../../helpers/show-modal-message/show-modal-message');
2010
2011require('../fos_user/directives/unique-user');
2012
2013angular.module('far.camp', [
2014	'ngTouch',
2015	'ngMessages',
2016	'angularFileUpload',
2017	'ui.select',
2018	'ui.bootstrap',
2019	'dekky.pagination',
2020	'dekky.forms',
2021	'far.models.camp',
2022	'far.core',
2023	'far.forms.inviteUserForm',
2024	'dekky.forms.themes.inviteUser',
2025	'far.helpers.showModalMessage',
2026	'far.fos_user.uniqueUser'
2027]).value('formsConfig', {
2028	theme: '/dekky.forms/themes/far'
2029});
2030
2031},{"../../forms/inviteUserForm":151,"../../forms/themes/inviteUser/inviteUser.theme":163,"../../helpers/show-modal-message/show-modal-message":167,"../../models/camp/camp":187,"../../modules/forms/forms":244,"../../modules/pagination/pagination":341,"../core/core":38,"../fos_user/directives/unique-user":66}],18:[function(require,module,exports){
2032'use strict';
2033
2034angular.module('far.camp')
2035    .controller('DescriptionCampController', ["$log", "$http", "$window", "$timeout", "$q", "pagination", function ($log,
2036                                                  $http,
2037                                                  $window,
2038                                                  $timeout,
2039                                                  $q,
2040                                                  pagination) {
2041        var vm = {
2042            constructor: constructor,
2043            type: 5,
2044            camp:[],
2045            campId: null,
2046            data:""
2047        };
2048
2049        function constructor(campId) {
2050            vm.campId = campId;
2051                 return $http.get(Routing.generate('api_get_camp', {
2052                camp_id: vm.campId
2053                
2054            })).then(function (response) {
2055                var items = [];
2056                vm.totalPages = Math.ceil(response.headers('X-Total-Count') / count);
2057
2058                angular.forEach(response.data, function (item) {
2059                    camp.push(item);
2060                });
2061                console.log(response.data);
2062
2063               console.log(camp);
2064            }).catch(function (response) {
2065                $log.error(response);
2066                return $q.reject(response);
2067            });
2068            
2069        }
2070
2071  
2072        //nextPage();
2073
2074        return vm;
2075    }]);
2076
2077},{}],19:[function(require,module,exports){
2078'use strict';
2079
2080angular.module('far.camp')
2081    .controller('CampEditController', ["$window", "autocomplete", "Camp", "form", "showModalMessage", function ($window, autocomplete, Camp, form, showModalMessage) {
2082        var vm = {
2083            progress: true,
2084            submitted: false,
2085            show_error: false,
2086            camp: null,
2087            form: {},
2088            fields: form('camp'),
2089            constructor: function (camp) {
2090                if (camp) {
2091                    vm.form = Camp.get(camp, function () {
2092                        vm.progress = false;
2093                    });
2094                } else {
2095                    vm.form = Camp.new();
2096                    vm.progress = false;
2097                }
2098            },
2099            submit: function () {
2100                if (vm.submitted) {
2101                    return false;
2102                }
2103
2104                vm.submitted = true;
2105
2106                vm.form.save()
2107                    .then(function (response) {
2108                        document.location.href = Routing.generate('camp_events', {id: response.data.id});
2109                    }, function errorCallback(response) {
2110                        vm.submitted = false;
2111                    });
2112            },
2113            autoCompleteSelect: {
2114                country: null,
2115                region: null
2116            }
2117        };
2118
2119        vm.fields
2120            .addField('name', 'text', {
2121                validators: {
2122                    required: true
2123                },
2124                options: {
2125                    placeholder: 'Название'
2126                }
2127            })
2128            .addField('country', 'uiSelect', {
2129                validators: {
2130                    required: false
2131                },
2132                options: {
2133                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
2134                    class: 'form__ui-select width-650'
2135                },
2136                uiSelectOptions: {
2137                    matchTitle: '{{ $select.selected.name }} ',
2138                    choicesTitle: '{{ item.name }}',
2139                    match: {
2140                        placeholder: 'Страна',
2141                        allowClear: true
2142                    },
2143                    choices: {
2144                        repeat: 'item in field.items track by item.id',
2145                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Country", "country")',
2146                        refreshDelay: 0
2147                    },
2148                    refreshAutoComplete: autocomplete.refreshAutoComplete,
2149                    onSelect: function (item) {
2150                        if (item) {
2151                            vm.autoCompleteSelect.country = item.id;
2152                            vm.autoCompleteSelect.region = null;
2153
2154                            vm.fields.$fields.region.items = [];
2155
2156                            vm.form.country = item;
2157                        }
2158                    }
2159                }
2160            }, autocomplete.get('country'))
2161            .addField('region', 'uiTypeahead', {
2162                validators: {
2163                    required: false
2164                },
2165                options: {
2166                    class: 'form__item',
2167                    placeholder: 'Регион',
2168                    uibTypeahead: "row as row.name for row in field.refreshAutoComplete($viewValue, 'Region')"
2169                },
2170                fieldData: {
2171                    clearBtn: true,
2172                    refreshAutoComplete: function (name, term) {
2173                        return autocomplete.refreshAutoComplete(name, term, null, vm.autoCompleteSelect)
2174                    }
2175                }
2176            })
2177            .addField('phone', 'text', {
2178                validators: {
2179                    required: false
2180                },
2181                options: {
2182                    placeholder: 'Телефон'
2183                }
2184            })
2185            .addField('email', 'text', {
2186                validators: {
2187                    required: false
2188                },
2189                options: {
2190                    placeholder: 'E-mail'
2191                }
2192            })
2193            .addField('www_site', 'text', {
2194                validators: {
2195                    required: false
2196                },
2197                options: {
2198                    placeholder: 'Сайт'
2199                }
2200            })
2201            .addField('www_vk', 'text', {
2202                validators: {
2203                    required: false
2204                },
2205                options: {
2206                    placeholder: 'Вконтакте'
2207                }
2208            })
2209            .addField('www_fb', 'text', {
2210                validators: {
2211                    required: false
2212                },
2213                options: {
2214                    placeholder: 'Facebook'
2215                }
2216            })
2217            .addField('www_in', 'text', {
2218                validators: {
2219                    required: false
2220                },
2221                options: {
2222                    placeholder: 'Instagram'
2223                }
2224            })
2225            .addField('general_data', 'textarea', {
2226             
2227                options: {
2228                    redactor: true,
2229                    placeholder: 'Описание лагеря',
2230                    class: 'form__item'
2231                }
2232            })
2233            .addField('image', 'imageUpload', {
2234                validators: {
2235                    required: false
2236                },
2237                uploader: {
2238                    url: Routing.generate('api_upload_post_avatar', {thumb: 'avatar_relative'}),
2239                    autoUpload: true,
2240                    removeAfterUpload: true,
2241                    onWhenAddingFileFailed: function (item, filter) {
2242                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
2243                        showModalMessage(message);
2244                    },
2245                    onErrorItem: function () {
2246                        showModalMessage('Невозможно загрузить файл на сервер');
2247                    },
2248                    onSuccessItem: function (item, response) {
2249                        vm.form.image = response;
2250                    }
2251                }
2252            })
2253            .addField('director', 'text', {
2254                validators: {
2255                    required: false
2256                },
2257                options: {
2258                    placeholder: 'Директор'
2259                }
2260            });
2261
2262        return vm;
2263    }]);
2264
2265},{}],20:[function(require,module,exports){
2266'use strict';
2267
2268angular.module('far.camp')
2269    .controller('EventsCampController', ["$log", "$http", "$window", "$timeout", "$q", "pagination", function ($log,
2270                                                  $http,
2271                                                  $window,
2272                                                  $timeout,
2273                                                  $q,
2274                                                  pagination) {
2275        var vm = {
2276            constructor: constructor,
2277            pagination: pagination('events', {next: nextPage, itemsOnPage: 4}),
2278            type: 5,
2279            filter: {
2280                period: 'all',
2281                eventData: null
2282            },
2283            campId: null,
2284            personalEvents: [],
2285            events: []
2286        };
2287
2288        function constructor(campId) {
2289            vm.campId = campId;
2290            vm.pagination.clear();
2291        }
2292
2293        function nextPage(page, count) {
2294            var eventData = {};
2295
2296            if (vm.filter.eventData) {
2297                eventData[vm.filter.eventData] = true;
2298            }
2299
2300            return $http.get(Routing.generate('api_event_get_eventplans', {
2301                camp_id: vm.campId,
2302                type: vm.type,
2303                offset: (page - 1) * count,
2304                limit: count,
2305                period: vm.filter.period,
2306                event_data: eventData
2307            })).then(function (response) {
2308                var items = [];
2309                vm.totalPages = Math.ceil(response.headers('X-Total-Count') / count);
2310
2311                angular.forEach(response.data, function (item) {
2312                    items.push(item);
2313                });
2314
2315                return items;
2316            }).catch(function (response) {
2317                $log.error(response);
2318                return $q.reject(response);
2319            });
2320        }
2321
2322        //nextPage();
2323
2324        return vm;
2325    }]);
2326
2327},{}],21:[function(require,module,exports){
2328'use strict';
2329
2330angular.module('far.camp')
2331    .controller('CampRoutesController', ["$log", "$http", "$window", "$timeout", "$q", "pagination", function ($log,
2332                                                  $http,
2333                                                  $window,
2334                                                  $timeout,
2335                                                  $q,
2336                                                  pagination) {
2337        var vm = {
2338            constructor: constructor,
2339            pagination: pagination('events', {next: nextPage, itemsOnPage: 4}),
2340            filter: {
2341                period: 'all',
2342                eventData: null
2343            },
2344            campId: null,
2345            personalEvents: [],
2346            events: [],
2347	    getMountainRouteUrl: function (route) {
2348		return Routing.generate('page_mountainroute_index', {'id': route.id});
2349	    },
2350	    getPeaksStringForRoute: function (route) {
2351                return route.mountain_peaks.map(function(peak) {
2352                        var _return = [];
2353
2354                        if ( peak.name ) {
2355                                _return.push(peak.name);
2356                        }
2357
2358                        return _return.join(', ');
2359                }).join(' - ');
2360	    },
2361	    getHeightStringForRoute: function (route) {
2362		var _return = [];
2363                route.mountain_peaks.map(function(peak) {
2364                        _return.push(peak.height);
2365                });
2366                if(_return.length > 1) {
2367                        return '';
2368                }
2369                return _return[0];
2370	    }
2371        };
2372
2373        function constructor(campId) {
2374            vm.campId = campId;
2375            vm.pagination.clear();
2376        }
2377
2378        function nextPage(page, count) {
2379            var eventData = {};
2380
2381            if (vm.filter.eventData) {
2382                eventData[vm.filter.eventData] = true;
2383            }
2384
2385            return $http.get(Routing.generate('api_entities_get_mountainroutes', {
2386                camp_id: vm.campId,
2387                offset: (page - 1) * count,
2388                limit: count
2389            })).then(function (response) {
2390                var items = [];
2391                vm.totalPages = Math.ceil(response.headers('X-Total-Count') / count);
2392
2393                angular.forEach(response.data, function (item) {
2394                    items.push(item[0]);
2395                });
2396
2397                return items;
2398            }).catch(function (response) {
2399                $log.error(response);
2400                return $q.reject(response);
2401            });
2402        }
2403
2404        return vm;
2405    }]);
2406
2407},{}],22:[function(require,module,exports){
2408require('./club.module');
2409require('./controllers/edit.controller');
2410require('./controllers/membership.controller');
2411require('./controllers/members_list.controller');
2412require('./controllers/events.controller');
2413
2414},{"./club.module":23,"./controllers/edit.controller":24,"./controllers/events.controller":25,"./controllers/members_list.controller":26,"./controllers/membership.controller":27}],23:[function(require,module,exports){
2415'use strict';
2416
2417require('../core/core');
2418require('../../modules/pagination/pagination');
2419require('../../modules/forms/forms');
2420
2421require('../../models/user/userMembership');
2422require('../../models/club/club');
2423
2424require('../../forms/inviteUserForm');
2425require('../../forms/clubEditForm');
2426require('../../forms/themes/inviteUser/inviteUser.theme');
2427
2428require('../../helpers/show-modal-message/show-modal-message');
2429
2430require('../fos_user/directives/unique-user');
2431
2432angular.module('far.club', [
2433	'ngTouch',
2434	'ngMessages',
2435	'angularFileUpload',
2436	'ui.select',
2437	'ui.bootstrap',
2438	'dekky.pagination',
2439	'dekky.forms',
2440	'far.models.userMembership',
2441	'far.models.club',
2442	'far.core',
2443	'far.forms.inviteUserForm',
2444	'far.forms.clubEditForm',
2445	'dekky.forms.themes.inviteUser',
2446	'far.helpers.showModalMessage',
2447	'far.fos_user.uniqueUser'
2448]).value('formsConfig', {
2449	theme: '/dekky.forms/themes/far'
2450});
2451
2452},{"../../forms/clubEditForm":141,"../../forms/inviteUserForm":151,"../../forms/themes/inviteUser/inviteUser.theme":163,"../../helpers/show-modal-message/show-modal-message":167,"../../models/club/club":190,"../../models/user/userMembership":232,"../../modules/forms/forms":244,"../../modules/pagination/pagination":341,"../core/core":38,"../fos_user/directives/unique-user":66}],24:[function(require,module,exports){
2453'use strict';
2454
2455angular.module('far.club')
2456    .controller('ClubEditController', ["$window", "autocomplete", "Club", "clubEditForm", "http", function ($window, autocomplete, Club, clubEditForm, http) {
2457        var vm = {
2458            progress: true,
2459            submitted: false,
2460            show_error: false,
2461            club: null,
2462            form: {},
2463            fields: clubEditForm,
2464            constructor: function (club) {
2465                if ( club ) {
2466                    vm.form = Club.get(club, function() {
2467                        if ( vm.form.country ) {
2468                            vm.form.country = {
2469                                name: vm.form.country
2470                            }
2471                        }
2472
2473                        vm.progress = false;
2474                    });
2475                } else {
2476                    vm.form = Club.new({country: {
2477                        name: 'Россия',
2478                        id: 150
2479                    }});
2480                    vm.progress = false;
2481                }
2482            },
2483            submit: function () {
2484                if ( vm.submitted ) {
2485                    return false;
2486                }
2487
2488                vm.submitted = true;
2489
2490                vm.form.save()
2491                    .then(function (response) {
2492                        document.location.href=Routing.generate('club_members', {id: response.data.id});
2493                    }, function errorCallback(response) {
2494                        response = http.authenticationListener(response);
2495                        
2496                        vm.submitted = false;
2497                    });
2498            }
2499        };
2500
2501        vm.fields.$fields.user.uiSelectOptions.onSelect = function(item) {
2502            if (item) { vm.form.user = item; }
2503        };
2504        vm.fields.$fields.avatar.uploader.onSuccessItem= function (item, response) {
2505            vm.form.avatar = response;
2506        };
2507
2508        return vm;
2509    }]);
2510
2511},{}],25:[function(require,module,exports){
2512'use strict';
2513
2514angular.module('far.club')
2515    .controller('EventsClubController', ["$log", "$http", "$window", "$timeout", "$q", "pagination", function ($log,
2516                                                  $http,
2517                                                  $window,
2518                                                  $timeout,
2519                                                  $q,
2520                                                  pagination) {
2521        var vm = {
2522            constructor: constructor,
2523            pagination: pagination('events', {next: nextPage, itemsOnPage: 4}),
2524            type: 4,
2525            filter: {
2526                period: 'all',
2527                eventData: null
2528            },
2529            clubId: null,
2530            personalEvents: [],
2531            events: []
2532        };
2533
2534        function constructor(clubId) {
2535            vm.clubId = clubId;
2536            vm.pagination.clear();
2537        }
2538
2539        function nextPage(page, count) {
2540            var eventData = {};
2541
2542            if (vm.filter.eventData) {
2543                eventData[vm.filter.eventData] = true;
2544            }
2545
2546            return $http.get(Routing.generate('api_event_get_eventplans', {
2547                club_id: vm.clubId,
2548                type: vm.type,
2549                offset: (page - 1) * count,
2550                limit: count,
2551                period: vm.filter.period,
2552                event_data: eventData
2553            })).then(function (response) {
2554                var items = [];
2555                vm.totalPages = Math.ceil(response.headers('X-Total-Count') / count);
2556
2557                angular.forEach(response.data, function (item) {
2558                    items.push(item);
2559                });
2560
2561                return items;
2562            }).catch(function (response) {
2563                $log.error(response);
2564                return $q.reject(response);
2565            });
2566        }
2567
2568        return vm;
2569    }]);
2570
2571},{}],26:[function(require,module,exports){
2572'use strict';
2573angular.module('far.club')
2574    .controller('ClubMembersListController', ["$filter", "$log", "$scope", "$window", "$http", "form", "autocomplete", "userMembership", "formsUtils", "inviteUserForm", "http", function ($filter, $log, $scope, $window, $http, form, autocomplete, userMembership, formsUtils, inviteUserForm, http) {
2575	var vm = {
2576	    progress: true,
2577            submitted: false,
2578            show_error: false,
2579            club_required: true,
2580            club_checkbox: false,
2581            max: null,
2582            club: null,
2583            users: [],
2584	    members_active:[],
2585	    members_active_paid:[],
2586            members_stopped:[],
2587            form: {},
2588            autoCompleteSelect: {
2589                country: null,
2590                region: null,
2591                city: null
2592            },
2593            submit: function () {
2594                vm.submitted = true;
2595                vm.show_error = true;
2596
2597                if ( !$scope.membershipForm.$valid ) {
2598                   return false;
2599                }
2600
2601            },
2602            constructor: function (user, club) {
2603		    vm.members_active =[];
2604		    vm.members_active_paid =[];
2605                    vm.members_stopped =[];
2606                    vm.members_new = [];
2607                    vm.members_invite = [];
2608                    vm.club = club;
2609		 
2610
2611                    $http.get(Routing.generate('api_get_club_users', {club: vm.club}))
2612                        .then(function (response) {
2613				console.log(response);
2614			
2615                            response.data.forEach(function(clubUser) {
2616				
2617                                if ( clubUser.member_card && clubUser.member_date_end ) {
2618                                    clubUser.fio_desc += '         Действующий до ' + $filter('date')(clubUser.member_date_end, "dd-MM-yyyy");
2619                                        if (
2620                                            $filter('date')(clubUser.member_date_end, "yyyy") > $filter('date')(new Date(), "yyyy")
2621                                            || ($filter('date')(clubUser.member_date_end, "yyyy") == $filter('date')(new Date(), "yyyy") && ($filter('date')(new Date(), "M") != 11 && $filter('date')(new Date(), "M") != 12) )
2622                                        ) {
2623                                            clubUser.disabled = true;
2624						vm.members_active_paid.push(clubUser);
2625                                        }
2626					 else{
2627						   vm.members_active.push(clubUser);
2628					      }
2629					  }
2630				            else{
2631				                vm.members_active.push(clubUser);
2632				
2633				                }
2634
2635
2636                            });
2637                        //    vm.progress = false;
2638                        }, function errorCallback(response) {
2639                            $log.error(response);
2640                        });
2641            }
2642                 };
2643
2644        return vm;
2645    }]);
2646
2647},{}],27:[function(require,module,exports){
2648'use strict';
2649
2650angular.module('far.club')
2651    .controller('ClubMembershipController', ["$filter", "$log", "$scope", "$window", "$http", "form", "autocomplete", "userMembership", "formsUtils", "inviteUserForm", "http", function ($filter, $log, $scope, $window, $http, form, autocomplete, userMembership, formsUtils, inviteUserForm, http) {
2652        var vm = {
2653            progress: true,
2654            submitted: false,
2655            show_error: false,
2656            club_required: true,
2657            club_checkbox: false,
2658            max: null,
2659            club: null,
2660            users: [],
2661	    members_active:[],
2662	    members_active_paid:[],
2663            members_stopped:[],
2664            form: {},
2665            autoCompleteSelect: {
2666                country: null,
2667                region: null,
2668                city: null
2669            },
2670            submit: function () {
2671                vm.submitted = true;
2672                vm.show_error = true;
2673
2674                if ( !$scope.membershipForm.$valid ) {
2675                   return false;
2676                }
2677
2678                vm.form.save()
2679                    .then(function () {
2680                        var data = {
2681                            members: [],			   			
2682                            members_new: [],
2683                            members_invite: []                        };
2684
2685                        if ( vm.form.members_active.length ) {
2686                            angular.forEach(vm.form.members_active, function(member) {
2687                                data.members.push(member.id);
2688                            });
2689                        }
2690			 if ( vm.form.members_stopped.length ) {
2691                            angular.forEach(vm.form.members_stopped, function(member) {
2692                                data.members.push(member.id);
2693                            });
2694                        }
2695
2696
2697                        if ( vm.form.members_new.length ) {
2698                            angular.forEach(vm.form.members_new, function(member_new) {
2699                                data.members_new.push(member_new.id);
2700                            });
2701                        }
2702
2703                        if ( vm.form.members_invite.length ) {
2704                            data.members_invite = angular.merge([], vm.form.members_invite);
2705                        }
2706
2707                        $http.post(Routing.generate('api_post_club_membership', {club: vm.club}), data)
2708                            .then(function (response) {
2709                                $window.location.href = response.data.url;
2710                            }, function errorCallback(response) {
2711                                $log.error(response);
2712                            });
2713                    }, function errorCallback(response) {
2714                        response = http.authenticationListener(response);
2715
2716                        vm.submitted = false;
2717
2718                        $log.error(response);
2719                    });
2720            },
2721            fields: form('ClubMembership'),
2722            constructor: function (user, club,fee, price, max) {
2723                vm.form = userMembership.get(user, function () {
2724                    vm.form.members = [];
2725		    vm.form.members_active =[];
2726		    vm.form.members_active_paid =[];
2727                    vm.form.members_stopped =[];
2728                    vm.form.members_new = [];
2729                    vm.form.members_invite = [];
2730                    vm.form.counter = 1;
2731                    vm.far_fee = price;
2732                    vm.club = club;
2733		    vm.local_fee=fee?fee:0;
2734		    vm.form.price=vm.far_fee;
2735		   if(vm.local_fee)
2736			vm.form.price=vm.form.price+vm.local_fee;
2737		    vm.form.confirmation=true;
2738			
2739
2740                    $http.get(Routing.generate('api_get_club_users', {club: vm.club}))
2741                        .then(function (response) {
2742                            response.data.forEach(function(clubUser) {
2743                                if ( clubUser.member_card && clubUser.member_date_end ) {
2744                                    clubUser.fio_desc += '         Действующий до ' + $filter('date')(clubUser.member_date_end, "dd-MM-yyyy");
2745                                        if (
2746                                            $filter('date')(clubUser.member_date_end, "yyyy") > $filter('date')(new Date(), "yyyy")
2747                                            || ($filter('date')(clubUser.member_date_end, "yyyy") == $filter('date')(new Date(), "yyyy") && ($filter('date')(new Date(), "M") != 11 && $filter('date')(new Date(), "M") != 12) )
2748                                        ) {
2749                                            clubUser.disabled = true;
2750						vm.members_active_paid.push(clubUser);
2751
2752                                        }
2753					else{
2754						vm.members_active.push(clubUser);
2755
2756					}
2757
2758
2759                                }
2760				else{
2761				vm.members_active.push(clubUser);
2762				
2763				}
2764
2765                                vm.users.push(clubUser);
2766                            });
2767
2768                            vm.progress = false;
2769                        }, function errorCallback(response) {
2770                            $log.error(response);
2771                        });
2772                });
2773            },
2774            counter: function (type) {
2775                if (type == 1) {
2776                    if ( vm.form.counter < vm.max ) {
2777                        vm.form.counter++;
2778                    }
2779                } else {
2780                    if ( vm.form.counter > 1 ) {
2781                        vm.form.counter--;
2782                    }
2783                }
2784            },
2785            getCounter: function () {
2786                return vm.form.counter + ' ' + formsUtils.numEnding( vm.form.counter, ['год', 'года', 'лет'] );
2787            }
2788        };
2789
2790        vm.fields
2791            .addField('members_active', 'checkboxCollection', {
2792                checkbox: {
2793                    label: 'fio_desc',
2794                    model: 'selected'
2795                }
2796            }, vm.members_active)
2797	.addField('members_active_paid', 'checkboxCollection', {
2798                checkbox: {
2799                    label: 'fio_desc',
2800                    model: 'selected'
2801                }
2802            }, vm.members_active_paid)
2803
2804	 
2805            .addField('members_new', 'userSelect', {
2806                uiSelectOptions: {
2807                    match: {
2808                        placeholder: 'Выберите участника...'
2809                    },
2810                    choices: {
2811                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "members_new",{unpaid:""})'
2812                    },
2813                    refreshAutoComplete: function(search, term, object) {
2814                        var users = [];
2815                       if ( vm.users.length ) {
2816                            for ( var i in vm.users ) {
2817                                users.push( vm.users[i].id );
2818                            }
2819                        }
2820                        if ( vm.form.members_new.length ) {
2821                            for ( var i in vm.form.members_new ) {
2822                                if ( vm.form.members_new[i].id ) {
2823				users.push( vm.form.members_new[i].id );
2824                                    
2825                                }
2826                            }
2827                        }
2828
2829                        return autocomplete.refreshAutoComplete(search, term, object, {
2830                            not_id: users,
2831			    unpaid: true
2832                        });
2833                    },
2834                    onSelect: function (item, model, options) {
2835                        if (item) {
2836                            vm.form.members_new[options.index] = item;
2837                        }
2838                    }
2839                }
2840            }, autocomplete.get('members_new'))
2841            .addField('members_invite', 'collection', {
2842                validators: {
2843                    required: true
2844                },
2845                label: 'Пригласить участника',
2846                buttons: {
2847                    add: 'Пригласить участника',
2848                    remove: 'Удалить участника'
2849                },
2850                fieldData: {
2851                    doDelete: function(item, model, $index) {
2852                        vm.form.members_invite.splice($index, 1);
2853
2854                        item.deleted_at = new Date();
2855                    },
2856                    filterArray: function(item) {
2857                        return !item.deleted_at;
2858                    },
2859                    ngRepeat: 'item in model|filter:field.filterArray track by $index'
2860                }
2861            }, inviteUserForm)
2862            .addField('phone', 'text', {
2863                validators: {
2864                    required: true
2865                },
2866                options: {
2867                    placeholder: 'Телефон'
2868                }
2869            })
2870            .addField('email', 'text', {
2871                validators: {
2872                    required: true
2873                },
2874                options: {
2875                    placeholder: 'E-mail'
2876                }
2877            })
2878            .addField('last_name', 'text', {
2879                validators: {
2880                    required: true
2881                },
2882                options: {
2883                    placeholder: 'Фамилия'
2884                }
2885            })
2886            .addField('first_name', 'text', {
2887                validators: {
2888                    required: true
2889                },
2890                options: {
2891                    placeholder: 'Имя'
2892                }
2893            })
2894            .addField('middle_name', 'text', {
2895                validators: {
2896                    required: false
2897                },
2898                options: {
2899                    placeholder: 'Отчество'
2900                }
2901            })
2902            .addField('counter', 'text', {
2903                validators: {
2904                    required: true,
2905                    numericOnly: ''
2906                },
2907                options: {
2908                    placeholder: '1',
2909                    class: 'form-counter__input',
2910                    maxlength: 2
2911                }
2912            })
2913            .addField('country', 'uiSelect', {
2914                validators: {
2915                    required: true
2916                },
2917                options: {
2918                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
2919                    class: 'form__ui-select width-350'
2920                },
2921                uiSelectOptions: {
2922                    matchTitle: '{{ $select.selected.name }} ',
2923                    choicesTitle: '{{ item.name }}',
2924                    match: {
2925                        placeholder: 'Страна',
2926                        allowClear: true
2927                    },
2928                    choices: {
2929                        repeat: 'item in field.items track by item.id',
2930                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Country", "country")',
2931                        refreshDelay: 0
2932                    },
2933                    refreshAutoComplete: autocomplete.refreshAutoComplete,
2934                    onSelect: function (item) {
2935                        if (item) {
2936                            vm.autoCompleteSelect.country = item.id;
2937                            vm.autoCompleteSelect.region = null;
2938                            vm.autoCompleteSelect.city = null;
2939
2940                            vm.form.country = item;
2941
2942                            vm.fields.$fields.region.items = [];
2943                            vm.fields.$fields.city.items = [];
2944                        }
2945                    }
2946                },
2947                fieldData: {
2948                    name: 'country'
2949                }
2950            }, autocomplete.get('country'))
2951            .addField('region', 'uiTypeahead', {
2952                validators: {
2953                    required: true
2954                },
2955                label: null,
2956                options: {
2957                    class: 'form__item',
2958                    placeholder: 'Регион',
2959                    tabindex: 10,
2960                    uibTypeahead: "row as row.name for row in field.refreshAutoComplete($viewValue, 'Region')"
2961                },
2962                fieldData: {
2963                    clearBtn: true,
2964                    refreshAutoComplete: function (name, term) {
2965                        return autocomplete.refreshAutoComplete(name, term, null, vm.autoCompleteSelect)
2966                    }
2967                }
2968            })
2969            .addField('city', 'uiTypeahead', {
2970                validators: {
2971                    required: true
2972                },
2973                label: null,
2974                options: {
2975                    class: 'form__item',
2976                    placeholder: 'Населенный пункт',
2977                    uibTypeahead: "row as row.name for row in field.refreshAutoComplete($viewValue, 'City')"
2978                },
2979                fieldData: {
2980                    clearBtn: true,
2981                    refreshAutoComplete: function (name, term) {
2982                        if (angular.isObject(vm.form.region)) {
2983                            vm.autoCompleteSelect.region = vm.form.region.id;
2984                        } else {
2985                            vm.autoCompleteSelect.region = null;
2986                        }
2987
2988                        return autocomplete.refreshAutoComplete(name, term, null, vm.autoCompleteSelect)
2989                    }
2990                }
2991            })
2992            .addField('post_index', 'text', {
2993                validators: {
2994                    required: true,
2995                    numericOnly: ''
2996                },
2997                options: {
2998                    placeholder: 'Индекс'
2999                }
3000            })
3001            .addField('address', 'text', {
3002                validators: {
3003                    required: true
3004                },
3005                options: {
3006                    placeholder: 'Улица'
3007                }
3008            })
3009            .addField('house', 'text', {
3010                validators: {
3011                    required: true
3012                },
3013                options: {
3014                    placeholder: 'Дом'
3015                }
3016            })
3017            .addField('building', 'text', {
3018                validators: {
3019                    required: false
3020                },
3021                options: {
3022                    placeholder: 'Кор.'
3023                }
3024            })
3025            .addField('apartment', 'text', {
3026                validators: {
3027                    required: false
3028                },
3029                options: {
3030                    placeholder: 'Кв.'
3031                }
3032            })
3033        ;
3034
3035        return vm;
3036    }]);
3037
3038},{}],28:[function(require,module,exports){
3039require('./committee.module');
3040require('./controllers/index.controller');
3041require('./controllers/edit.controller');
3042
3043},{"./committee.module":29,"./controllers/edit.controller":30,"./controllers/index.controller":31}],29:[function(require,module,exports){
3044'use strict';
3045
3046require('../core/core');
3047require('../../modules/pagination/pagination');
3048require('../../modules/forms/forms');
3049require('../../modules/ui/events-calendar/events-calendar');
3050
3051require('../../helpers/show-modal-message/show-modal-message');
3052
3053require('../documents/documents.module');
3054require('../../models/committee/committee');
3055require('../../redactor/redactor.js');
3056require('../../redactor/lang/ru.js');
3057
3058
3059angular.module('far.committee', [
3060	'ngTouch',
3061	'angularFileUpload',
3062	'ui.select',
3063	'ui.bootstrap',
3064	'dekky.pagination',
3065	'dekky.forms',
3066	'far.models.rank',
3067	'far.models.rankSeason',
3068	'far.core',
3069	'far.models.committee',
3070	'far.helpers.showModalMessage',
3071    'far.ui.eventsCalendar',
3072	'templates',
3073	'far.documents.search'
3074]).value('formsConfig', {
3075	theme: '/dekky.forms/themes/far'
3076});
3077
3078},{"../../helpers/show-modal-message/show-modal-message":167,"../../models/committee/committee":191,"../../modules/forms/forms":244,"../../modules/pagination/pagination":341,"../../modules/ui/events-calendar/events-calendar":344,"../../redactor/lang/ru.js":349,"../../redactor/redactor.js":350,"../core/core":38,"../documents/documents.module":46}],30:[function(require,module,exports){
3079'use strict';
3080
3081angular.module('far.committee')
3082    .controller('CommitteeEditController', ["$log", "Committee", "committeeForm", "showModalMessage", function ($log, Committee, committeeForm, showModalMessage) {
3083        var vm = {
3084            progress: true,
3085            submitted: false,
3086            form: {},
3087            fields: committeeForm,
3088            constructor: function (committee) {
3089                    vm.form = Committee.get(committee, function() {
3090                        vm.progress = false;
3091                    });
3092
3093
3094
3095            },
3096            submit: function () {
3097                vm.form.save()
3098                    .then(function (response) {
3099                        document.location.href=Routing.generate('committee_view', {url: response.data.url});
3100                    })
3101                    .catch(function (response) {
3102                        $log.error(response);
3103                        showModalMessage('Не удалось сохранить изменения на сервере. Попробуйте повторить попытку через некоторое время.');
3104                    });
3105            }
3106        };
3107
3108        return vm;
3109    }]);
3110
3111},{}],31:[function(require,module,exports){
3112'use strict';
3113
3114angular.module('far.committee')
3115    .controller('CommitteeIndexController', ["$log", "$http", function ($log, $http) {
3116        var vm = {
3117            progress: false,
3118            construct: function (committee) {
3119                vm.form = { id: committee };
3120            }
3121        };
3122
3123        return vm;
3124    }]);
3125
3126},{}],32:[function(require,module,exports){
3127require('./competition.module.js');
3128require('./controllers/report.controller');
3129require('./controllers/request.controller');
3130
3131},{"./competition.module.js":33,"./controllers/report.controller":34,"./controllers/request.controller":35}],33:[function(require,module,exports){
3132'use strict';
3133
3134require('../core/core');
3135require('../../modules/forms/forms');
3136require('../../modules/maps/maps');
3137
3138require('../../models/competition/competition');
3139require('../../models/competition/competitionReport');
3140require('../../models/competition/competitionUserType');
3141
3142require('../../forms/competitionReportForm');
3143require('../../forms/competitionRequestForm');
3144
3145require('../../helpers/show-modal-message/show-modal-message');
3146require('../../helpers/users/users.module');
3147
3148require('../fos_user/directives/unique-user');
3149
3150require('../../modals/mountain-route-form/mountain-route-form');
3151require('../../modals/slider/slider');
3152
3153
3154angular.module('far.competition', [
3155    'ngTouch',
3156    'dndLists',
3157    'ngMessages',
3158    'angularFileUpload',
3159    'ui.select',
3160    'ui.bootstrap',
3161    'dekky.forms',
3162    'far.models.competition.competition',
3163    'far.models.competition.competitionReport',
3164    'far.models.competition.competitionUserType',
3165    'far.core',
3166    'far.maps',
3167    'far.forms.competitionReportForm',
3168    'far.forms.competitionRequestForm',
3169    'templates',
3170    'far.helpers.showModalMessage',
3171    'far.helpers.users',
3172    'far.fos_user.uniqueUser',
3173    'far.modals.slider'
3174]).value('formsConfig', {
3175    theme: '/dekky.forms/themes/far'
3176}).run(["$templateCache", function ($templateCache) {
3177    $templateCache.put('/far.competition/fields/partnersCollection.html',
3178        '<div ng-init="model = model || []" ng-model="model">' +
3179        '<div repeat-collection ng-init="fieldIndex = $index" ng-form="childForm">' +
3180        '<div class="form-group right">' +
3181        '<button class="btn-gold" type="button" ng-click="field.doDelete(item, model, $index)">{{ field.buttons.remove }}</button>' +
3182        '</div>' +
3183        '<form-row ng-model="item.name" field="field.childForm.$fields.name" field-index="fieldIndex"></form-row>' +
3184        '<p class="form__error" role="alert" ng-if="childForm.$$parentForm.$submitted && childForm.name.$error.required">Обязательное поле</p>' +
3185        '<form-row ng-model="item.url" field="field.childForm.$fields.url" field-index="fieldIndex"></form-row>' +
3186        '<p class="form__error" role="alert" ng-if="childForm.$$parentForm.$submitted" ng-messages="childForm.url.$error">' +
3187        '<span ng-message="required">Обязательное поле</span>' +
3188        '<span ng-message="url">Урл в неверном формате</span>' +
3189        '</p>' +
3190        '<form-row ng-model="item.logo" field="field.childForm.$fields.logo" field-index="fieldIndex"></form-row>' +
3191        '<div class="form__line"></div>' +
3192        '</div>' +
3193
3194        '<div class="form-group">' +
3195        '<button class="btn-standart" type="button" ng-click="field.addItem(model)">{{ field.buttons.add }}</button>' +
3196        '</div>' +
3197        '</div>'
3198    );
3199}]);
3200
3201},{"../../forms/competitionReportForm":142,"../../forms/competitionRequestForm":143,"../../helpers/show-modal-message/show-modal-message":167,"../../helpers/users/users.module":169,"../../modals/mountain-route-form/mountain-route-form":175,"../../modals/slider/slider":182,"../../models/competition/competition":192,"../../models/competition/competitionReport":193,"../../models/competition/competitionUserType":195,"../../modules/forms/forms":244,"../../modules/maps/maps":338,"../core/core":38,"../fos_user/directives/unique-user":66}],34:[function(require,module,exports){
3202'use strict';
3203
3204angular.module('far.competition').controller('CompetitionReportController', ["$rootScope", "$window", "$log", "competitionReportForm", "Competition", "CompetitionReport", "$scope", "FileUploader", function ($rootScope, $window, $log, competitionReportForm, Competition, CompetitionReport, $scope, FileUploader) {
3205    var vm = {
3206        progress: true,
3207        submitted: false,
3208        form: {},
3209        event: {},
3210        requestController: {},
3211        fields: competitionReportForm,
3212        eventType: null,
3213        eventUserTypes: {},
3214        event_competition_type: [],
3215        winners: {},
3216        btn: {
3217            accepted: false,
3218            submitted: false
3219        },
3220        init: function (eventId, eventReportEdit) {
3221            vm.event_competition_type.forEach(function (value) {
3222                vm.winners[value.id] = {
3223                    female: {},
3224                    male: {}
3225                };
3226
3227                for (var i = 1; i <= 3; i++) {
3228                    vm.winners[value.id].female[i] = [{}];
3229                    vm.winners[value.id].male[i] = [{}];
3230                }
3231            });
3232
3233            if (eventReportEdit) {
3234                vm.form = CompetitionReport.get(eventId, vm.eventUserTypes, function () {
3235                    if (vm.form.winners.length) {
3236                        vm.form.winners.forEach(function (user) {
3237                            if (user.people_xerox) {
3238                                var gender = 'female';
3239                            } else {
3240                                var gender = 'male';
3241                            }
3242
3243                            if (!vm.winners[user.event_competition_type.id][gender][user.place][0].id) {
3244                                vm.winners[user.event_competition_type.id][gender][user.place] = [];
3245                            }
3246
3247                            vm.winners[user.event_competition_type.id][gender][user.place].push(user.user);
3248                        });
3249                    }
3250
3251                    if (vm.form.documents_files.length > 0) {
3252                        vm.form.documents_files.forEach(function (serverFile) {
3253                            var newFile = new FileUploader.FileItem(vm.fields.$fields.documentsFiles.uploader, {
3254                                lastModifiedDate: new Date(),
3255                                size: 1e6,
3256                                name: serverFile.original_name
3257                            });
3258
3259                            newFile.progress = 100;
3260                            newFile.isUploaded = true;
3261                            newFile.isSuccess = true;
3262                            newFile.serverData = angular.merge({}, serverFile);
3263
3264                            vm.fields.$fields.documentsFiles.uploader.queue.push(newFile);
3265                        });
3266                    }
3267
3268                    vm.btn.accepted = vm.form.accepted;
3269                    vm.btn.submitted = vm.form.submitted;
3270
3271                    vm.progress = false;
3272                });
3273            } else {
3274                vm.form = CompetitionReport.new({
3275                    event_id: eventId,
3276                    winners: []
3277                }, vm.eventUserTypes);
3278
3279                vm.progress = false;
3280            }
3281        },
3282        sendReport: function () {
3283            vm.form.submitted = true;
3284            vm.form.accepted = false;
3285
3286            $scope.competitionReportForm.$submitted  = true;
3287
3288            vm.save();
3289        },
3290        sendAccepted: function () {
3291            vm.form.submitted = true;
3292            vm.form.accepted = true;
3293
3294            $scope.competitionReportForm.$submitted  = true;
3295
3296            vm.save();
3297        },
3298        save: function () {
3299            if ((vm.form.submitted || vm.form.accepted) && (vm.progress || $scope.competitionReportForm.$invalid)) {
3300                return;
3301            }
3302
3303            vm.form.documents_files = vm.documents_files;
3304
3305            vm.form.event = vm.requestController.getEventData();
3306
3307            vm.form.winners = [];
3308
3309            for (var type in vm.winners) {
3310                for (var gender in vm.winners[type]) {
3311                    for (var place in vm.winners[type][gender]) {
3312                        for (var i in vm.winners[type][gender][place]) {
3313                            if (vm.winners[type][gender][place][i].id != undefined) {
3314                                vm.form.winners.push({
3315                                    user: vm.winners[type][gender][place][i].id,
3316                                    event_competition_type: type,
3317                                    place: place,
3318                                    people_xerox: (gender == 'female')
3319                                });
3320                            }
3321                        }
3322                    }
3323                }
3324            }
3325
3326            var users = [];
3327
3328            for (var user_key in vm.form.users) {
3329                if (vm.form.users[ user_key ].user) {
3330                    users.push(vm.form.users[ user_key ]);
3331                }
3332            }
3333
3334            vm.form.users = users;
3335
3336            console.log(vm.form.users.length);
3337
3338            vm.form.save()
3339                .then(function (response) {
3340                    $window.location.href = Routing.generate('event_view', {id: response.data.id});
3341                }, function (response) {
3342
3343                });
3344        }
3345    };
3346
3347    vm.fields.$fields.safety.uiSelectOptions.onSelect = function (item, model, options) {
3348        vm.form.updateUser(options.index, item);
3349    };
3350
3351    vm.fields.$fields.judge.uiSelectOptions.onSelect = function (item, model, options) {
3352        vm.form.updateUser(options.index, item);
3353    };
3354
3355    vm.fields.$fields.winner.uiSelectOptions.onSelect = function (item, model, options) {
3356        if (typeof item == 'undefined') {
3357            delete vm.winners[options.type][options.gender][options.place][options.index];
3358        } else {
3359            vm.winners[options.type][options.gender][options.place][options.index] = item;
3360        }
3361    };
3362
3363    return vm;
3364}]);
3365
3366},{}],35:[function(require,module,exports){
3367'use strict';
3368
3369angular.module('far.competition').controller('CompetitionRequestController', ["$rootScope", "$window", "$log", "competitionRequestForm", "maps", "Geocoder", "Competition", "$scope", "partners", "CompetitionType", "FileUploader", function ($rootScope, $window, $log, competitionRequestForm, maps, Geocoder, Competition, $scope, partners, CompetitionType, FileUploader) {
3370    var geocoder = new Geocoder();
3371
3372    var vm = {
3373        progress: true,
3374        submitted: false,
3375        form: {},
3376        fields: competitionRequestForm,
3377        eventType: null,
3378        eventUserTypes: {},
3379        init: function () {
3380            if (arguments.length > 0) {
3381                vm.form = Competition.get(arguments[0], vm.eventUserTypes, function () {
3382                    vm.form.disciplines = vm.form.disciplines[0]
3383
3384                    var partnersWatch = $rootScope.$watch(function () {
3385                        return partners.list.length;
3386                    }, function (length) {
3387                        if (length > 0) {
3388                            var competitionPartnersLength = vm.form.partners.length;
3389
3390                            if (competitionPartnersLength) {
3391                                partners.list.forEach(function (partner) {
3392                                    if (length == competitionPartnersLength) {
3393                                        partner.selected = true;
3394                                    } else {
3395                                        vm.form.partners.forEach(function (selectedPartner) {
3396                                            if (partner.id == selectedPartner.id) {
3397                                                partner.selected = true;
3398                                            }
3399                                        });
3400                                    }
3401                                });
3402                            }
3403
3404                            partnersWatch();
3405                        }
3406                    });
3407
3408                    var typeWatch = $rootScope.$watch(function () {
3409                        return Object.keys(CompetitionType.list).length;
3410                    }, function (length) {
3411
3412                        if (length > 0) {
3413                            var competitionTypeList = CompetitionType.list[vm.form.disciplines.system_name];
3414
3415                            vm.fields.$fields.event_competition_type.items = competitionTypeList;
3416
3417                            if (vm.form.event_competition.event_competition_type.length) {
3418                                competitionTypeList.forEach(function (type) {
3419                                    if (competitionTypeList.length == vm.form.event_competition.event_competition_type.length) {
3420                                        type.selected = true;
3421                                    } else {
3422                                        vm.form.event_competition.event_competition_type.forEach(function (selectedType) {
3423                                            if (type.id == selectedType.id) {
3424                                                type.selected = true;
3425                                            }
3426                                        });
3427                                    }
3428                                });
3429                            }
3430
3431                            typeWatch();
3432                        }
3433                    });
3434
3435                    if (vm.form.coordinates) {
3436                        vm.map.center = vm.form.coordinates;
3437                        vm.map.markers = [angular.merge({id: 1}, vm.form.coordinates)];
3438                    }
3439
3440                    if (vm.form.background_image) {
3441                        if (Object.keys(vm.form.background_image).length) {
3442                            var backgroundImage = new FileUploader.FileItem(vm.fields.$fields.backgroundImage.uploader, {
3443                                lastModifiedDate: new Date(),
3444                                size: 1e6,
3445                                name: vm.form.background_image.image_name
3446                            });
3447
3448                            backgroundImage.progress = 100;
3449                            backgroundImage.isUploaded = true;
3450                            backgroundImage.isSuccess = true;
3451                            backgroundImage.serverData = angular.merge({}, vm.form.background_image);
3452
3453                            vm.fields.$fields.backgroundImage.uploader.queue.push(backgroundImage);
3454                        }
3455                    }
3456
3457                    vm.form.event_competition.documents_files.forEach(function (serverFile) {
3458                        var newFile = new FileUploader.FileItem(vm.fields.$fields.documentsFiles.uploader, {
3459                            lastModifiedDate: new Date(),
3460                            size: 1e6,
3461                            name: serverFile.original_name
3462                        });
3463
3464                        newFile.progress = 100;
3465                        newFile.isUploaded = true;
3466                        newFile.isSuccess = true;
3467                        newFile.serverData = angular.merge({}, serverFile);
3468
3469                        vm.fields.$fields.documentsFiles.uploader.queue.push(newFile);
3470                    });
3471                    console.log(vm.rc);
3472                    vm.progress = false;
3473                });
3474            } else {
3475                vm.form = Competition.new({
3476                    event_competition: {
3477                        users: [],
3478                        event_competition_type: []
3479                    },
3480                    type: vm.eventType,
3481                    partners: []
3482                }, vm.eventUserTypes);
3483
3484                vm.progress = false;
3485            }
3486        },
3487        submit: function () {
3488            if (vm.submitted || $scope.competitionRequestForm.$invalid) {
3489                return;
3490            }
3491
3492            vm.submitted = true;
3493            vm.progress = true;
3494
3495            if (vm.form.event_competition.accepted == undefined) {
3496                vm.form.event_competition.accepted = vm.fields.$fields.accepted.items[0];
3497            }
3498
3499            if (vm.map.markers.length > 0) {
3500                vm.form.latitude = vm.map.markers[0].latitude;
3501                vm.form.longitude = vm.map.markers[0].longitude;
3502            }
3503
3504            vm.form.event_competition.documents_files = vm.documents_files;
3505
3506            vm.form.save()
3507                .then(function (response) {
3508                    $window.location.href = Routing.generate('event_view', {id: response.data.id});
3509                }, function (response) {
3510                    $log.error(response);
3511
3512                    vm.submitted = false;
3513                    vm.progress = false;
3514                });
3515        },
3516        accepted: function () {
3517            vm.form.event_competition.accepted = vm.fields.$fields.accepted.items[1];
3518
3519            vm.submit();
3520        },
3521        reject: function () {
3522            vm.form.event_competition.accepted = vm.fields.$fields.accepted.items[2];
3523
3524            vm.submit();
3525        },
3526        map: {
3527            center: maps.getDefaultCenter(),
3528            zoom: maps.getDefaultZoom(),
3529            markers: [],
3530            events: {
3531                click: function (map, eventName, event) {
3532                    var marker = geocoder.getLatLngObject(event[0].latLng);
3533                    marker.id = 1;
3534                    vm.map.markers = [marker];
3535                }
3536            }
3537        },
3538        getEventData: function () {
3539            return {
3540                brief: vm.form.brief,
3541                description: vm.form.description
3542            }
3543        }
3544    };
3545
3546    vm.fields.$fields.user_director.uiSelectOptions.onSelect = function (item, model, options) {
3547        vm.form.event_competition.updateUser(options.index, item);
3548    };
3549
3550    vm.fields.$fields.user_main_judge.uiSelectOptions.onSelect = function (item, model, options) {
3551        vm.form.event_competition.updateUser(options.index, item);
3552    };
3553
3554    vm.fields.$fields.club.uiSelectOptions.onSelect = function (item) {
3555        vm.form.event_competition.club = item ? item : null;
3556    };
3557
3558    vm.fields.$fields.camp.uiSelectOptions.onSelect = function (item) {
3559        vm.form.camp = item ? item : null;
3560    };
3561
3562    vm.fields.$fields.location.options.ngBlur = function changeLocation() {
3563        if (vm.form.location) {
3564            geocoder.getLocationsByAddress(vm.form.location).then(function (response) {
3565                var marker = {id: 1};
3566
3567                if (response.result.length > 0) {
3568                    vm.map.center = geocoder.getLatLngObject(response.result[0].geometry.location);
3569                    angular.merge(marker, geocoder.getLatLngObject(response.result[0].geometry.location));
3570                    vm.map.markers = [marker];
3571                }
3572            })
3573        }
3574    };
3575
3576    return vm;
3577}]);
3578
3579},{}],36:[function(require,module,exports){
3580'use strict';
3581
3582angular.module('far.core')
3583    .controller('AppController', ["maps", function (maps) {
3584        var ac = {
3585            menu_show: false,
3586            hideMenu: hideMenu,
3587            map: {
3588                options: {
3589                    disableDefaultUI: true,
3590                    zoomControl: true,
3591                    scrollwheel: false,
3592                    styles: maps.getStyle()
3593                }
3594            }
3595        };
3596
3597        function hideMenu(event) {
3598            if (event.target.classList.contains('hamburger') || event.target.classList.contains('hamburger__ico')) {
3599                return;
3600            }
3601
3602            if (ac.menu_show) {
3603                ac.menu_show = false;
3604            }
3605        }
3606
3607        return ac;
3608    }]);
3609
3610},{}],37:[function(require,module,exports){
3611'use strict';
3612
3613angular.module('far.core')
3614    .directive('clickover', ["$document", "$timeout", function ($document, $timeout) {
3615        return {
3616            restrict: 'A',
3617            scope: {
3618                clickover: '='
3619            },
3620            link: function (scope, element) {
3621                $document.on('click', function (event) {
3622                    if (event.target != element[0] && !element.has(event.target)) {
3623                        if (typeof(scope.clickover) == 'function') {
3624                            $timeout(function () {
3625                                scope.clickover(event);
3626                            });
3627                        }
3628                    }
3629                });
3630            }
3631        };
3632    }]);
3633
3634},{}],38:[function(require,module,exports){
3635require('./core.module');
3636require('./app.controller');
3637require('./clickover.directive');
3638
3639},{"./app.controller":36,"./clickover.directive":37,"./core.module":39}],39:[function(require,module,exports){
3640'use strict';
3641
3642require('../../helpers/rawFilter/rawFilter');
3643require('../../modules/ui/ui');
3644require('../../modules/maps/maps');
3645
3646angular.module('far.core', [
3647        'ngCookies',
3648        'ngAnimate',
3649        'duScroll',
3650        'mgcrea.bootstrap.affix',
3651        'far.helpers.rawFilter',
3652        'far.ui',
3653        'far.maps'
3654    ])
3655    .config(['$httpProvider', function ($httpProvider) {
3656        $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
3657    }])
3658    .value('duScrollOffset', 85)
3659    .value('duScrollActiveClass', 'page-menu__item')
3660    .run(function () {
3661        var jqLite = angular.element;
3662
3663        jqLite.prototype.has = function (element) {
3664            var children = this.children(), i;
3665
3666            for (i = 0; i < children.length; i++) {
3667                if (children[i] == element) {
3668                    return true;
3669                }
3670            }
3671
3672            for (i = 0; i < children; i++) {
3673                var subChildren = jqLite(children[i]).children();
3674                if (subChildren.length > 0) {
3675                    for (var ii = 0; ii < subChildren.length; ii++) {
3676                        if (jqLite(subChildren[ii]).has(element)) {
3677                            return true;
3678                        }
3679                    }
3680
3681                }
3682            }
3683
3684            return false;
3685        };
3686    })
3687
3688},{"../../helpers/rawFilter/rawFilter":166,"../../modules/maps/maps":338,"../../modules/ui/ui":347}],40:[function(require,module,exports){
3689'use strict';
3690
3691angular.module('far.discipline')
3692    .controller('DisciplineIndexController', ["$log", "$http", function ($log, $http) {
3693        var vm = {
3694            progress: true,
3695            events: {},
3696            construct: function (discipline) {
3697                vm.form = { id: discipline };
3698                getEvents(discipline);
3699            }
3700        };
3701
3702        function getEvents(discipline) {
3703            $http.get(Routing.generate('api_discipline_get_discipline_events', {discipline: discipline}))
3704                .then(function (response) {
3705                    vm.events = angular.merge({}, response.data);
3706                    vm.progress = false;
3707                }, function errorCallback(response) {
3708                    $log.error(response);
3709                    showModalMessage('Невозможно загрузить мероприятия.');
3710                });
3711
3712            return vm.data;
3713        }
3714
3715        return vm;
3716    }]);
3717
3718},{}],41:[function(require,module,exports){
3719'use strict';
3720
3721angular.module('far.discipline')
3722    .controller('DisciplineNewsController', ["$log", "$http", function($log, $http) {
3723        var vm = {
3724            loaded: true,
3725            submitted: false,
3726            params: {
3727                limit: 10,
3728                offset: 0,
3729                discipline: null
3730            },
3731            total: {
3732                count: 0,
3733                pages: null
3734            },
3735            data: [],
3736            construct: function ( discipline ) {
3737                vm.params.discipline = discipline;
3738
3739                vm.submit();
3740            },
3741            submit: function ( next ) {
3742                if (vm.submitted) {
3743                    return false;
3744                }
3745
3746                if ( !next ) {
3747                    vm.params.offset = 0;
3748
3749                    vm.total.count = 0;
3750                    vm.total.pages = null;
3751
3752                    vm.data = [];
3753                }
3754
3755                vm.submitted = true;
3756
3757                $http.get(Routing.generate('api_get_newslist', vm.params)).then(function (response) {
3758                    vm.total.count = response.headers('X-Total-Count');
3759                    vm.total.pages = Math.ceil( vm.total.count / vm.params.limit );
3760
3761                    if ( response.data ) {
3762                        response.data.forEach(function(news) {
3763                            news['url'] = Routing.generate('news_view', {id: news.id});
3764
3765                            news.disciplines = news.disciplines.map(function (discipline) {
3766                                discipline['url'] = Routing.generate('discipline_index', {url: discipline.url});
3767
3768                                return discipline;
3769                            });
3770
3771                            vm.data.push(news);
3772                        });
3773                    }
3774
3775                    vm.submitted = false;
3776                    vm.loaded = false;
3777                }, function errorCallback(response) {
3778                    $log.error(response);
3779
3780                    vm.submitted = false;
3781                });
3782            },
3783            next: function () {
3784                vm.params.offset += vm.params.limit;
3785
3786                vm.submit( true );
3787            }
3788        };
3789
3790        return vm;
3791    }]);
3792
3793},{}],42:[function(require,module,exports){
3794'use strict';
3795
3796angular.module('far.discipline')
3797    .controller('DisciplineRankEditController', ["$rootScope", "$scope", "$log", "$http", "$window", "$location", "Rank", "RankSeason", function ($rootScope, $scope, $log, $http, $window, $location, Rank, RankSeason) {
3798        var vm = {
3799            progress: true,
3800            submitted: false,
3801            model: {
3802                values: []
3803            },
3804            title: [],
3805            seasonList: [],
3806            seasonModel: {},
3807            seasonModal: false,
3808            disciplineUrl: '',
3809            getRank: function () {
3810                vm.progress = true;
3811
3812                vm.model.title = [];
3813                vm.title = [];
3814
3815                vm.seasonList.map(function (season) {
3816                    if (season.id == vm.model.season) {
3817                        vm.title.push(season.name + ' год')
3818                    }
3819                });
3820
3821                vm.model.values = [];
3822
3823                vm.model = Rank.get(vm.model, function () {
3824                    if (vm.model.values.length) {
3825                        vm.model.values = vm.model.values.map(function (value) {
3826                            value.qualification = value.qualification.id.toString();
3827
3828                            return value;
3829                        });
3830                    }
3831
3832                    if (vm.model.values.length < 10) {
3833                        vm.addRankEmpty(10-vm.model.values.length)
3834                    }
3835
3836                    vm.progress = false;
3837                });
3838            },
3839            getRankSeason: function () {
3840                vm.seasonList = [];
3841
3842                $http.get(Routing.generate('api_discipline_get_discipline_rank_seasons'))
3843                    .then(function (response) {
3844                        response.data.forEach(function (item, index) {
3845                            if (index == 0 && vm.model.season == undefined) {
3846                                vm.model.season = item.id.toString();
3847                            }
3848
3849                            vm.seasonList.push(item);
3850                        });
3851
3852                        vm.getRank();
3853                    }, function (response) {
3854                        $log.error(response);
3855
3856                        vm.progress = false;
3857                    });
3858            },
3859            addRankEmpty: function (max) {
3860                for (var i = 0; i < max; i++) {
3861                    vm.model.values.push({
3862                        points: '',
3863                        name: '',
3864                        city: '',
3865                        age: '',
3866                        qualification: vm.rankValueQualification
3867                    });
3868                }
3869            },
3870            init: function () {
3871                vm.seasonModel = RankSeason.new();
3872
3873                vm.getRankSeason();
3874            },
3875            seasonSubmit: function () {
3876                if (vm.submitted || $scope.rankSeasonForm.$invalid) {
3877                    return;
3878                }
3879
3880                vm.submitted = true;
3881
3882                vm.seasonModel.save()
3883                    .then(function (response) {
3884                        vm.seasonModel.name = '';
3885
3886                        vm.model.season = response.data.id.toString();
3887
3888                        vm.getRankSeason();
3889
3890                        vm.seasonModal = false;
3891                        vm.submitted = false;
3892                    }, function () {
3893                        vm.seasonModel.name = '';
3894
3895                        vm.seasonModal = false;
3896                        vm.submitted = false;
3897                    });
3898            },
3899            submit: function () {
3900                if (vm.submitted) {
3901                    return false;
3902                }
3903
3904                vm.submitted = true;
3905
3906                vm.model
3907                    .save()
3908                    .then(function () {
3909                        $window.location.href = Routing.generate('discipline_rank', {url: vm.disciplineUrl});
3910                    }, function (response) {
3911                        $log.error(response);
3912
3913                        vm.submitted = true;
3914                    });
3915            }
3916        };
3917
3918        return vm;
3919    }]);
3920
3921},{}],43:[function(require,module,exports){
3922'use strict';
3923
3924angular.module('far.discipline')
3925    .controller('DisciplineRankController', ["$rootScope", "$scope", "$log", "$http", "$window", "Rank", function ($rootScope, $scope, $log, $http, $window, Rank) {
3926        var vm = {
3927            progress: true,
3928            submitted: false,
3929            model: {
3930                people_xerox: "0",
3931                values: []
3932            },
3933            title: {
3934                people_xerox: '',
3935                class: '',
3936                type: '',
3937                season: ''
3938            },
3939            url: '',
3940            url_params: {},
3941            title_array: [],
3942            seasonList: [],
3943            seasonModal: false,
3944            disciplineUrl: '',
3945            date: new Date(),
3946            getRank: function () {
3947                vm.progress = true;
3948
3949                vm.title_array = [];
3950                vm.url_params = {
3951                    url: vm.disciplineUrl,
3952                    gender: vm.model.people_xerox,
3953                    season: vm.model.season
3954                };
3955
3956                vm.title_array.push(vm.title.people_xerox);
3957
3958                if (vm.title.class) {
3959                    vm.title_array.push(vm.title.class);
3960                    vm.url_params.class = vm.model.class;
3961                }
3962
3963                if (vm.title.type) {
3964                    vm.title_array.push(vm.title.type);
3965                    vm.url_params.type = vm.model.type;
3966                }
3967
3968                vm.seasonList.map(function (season) {
3969                    if (season.id == vm.model.season) {
3970                        vm.title_array.push(season.name + ' год');
3971                    }
3972                });
3973
3974                vm.url = Routing.generate('discipline_rank_edit', vm.url_params);
3975
3976                vm.model.values = [];
3977
3978                vm.model = Rank.get(vm.model, function () {
3979                    vm.progress = false;
3980                });
3981            },
3982            getRankSeason: function () {
3983                $http.get(Routing.generate('api_discipline_get_discipline_rank_seasons'))
3984                    .then(function (response) {
3985                        response.data.forEach(function (item) {
3986                            if (item.name == vm.date.getFullYear() && vm.model.season == undefined) {
3987                                vm.model.season = item.id.toString();
3988                            }
3989
3990                            vm.seasonList.push(item);
3991                        });
3992
3993                        if (!vm.model.season) {
3994                            vm.model.season = vm.seasonList[0].id.toString();
3995                        }
3996
3997                        vm.getRank();
3998                    }, function (response) {
3999                        $log.error(response);
4000
4001                        vm.progress = false;
4002                    });
4003            },
4004            init: function () {
4005                vm.getRankSeason();
4006            }
4007        };
4008
4009        return vm;
4010    }]);
4011
4012},{}],44:[function(require,module,exports){
4013require('./discipline.module');
4014require('./controllers/index.controller');
4015require('./controllers/news.controller');
4016require('./controllers/rank.controller');
4017require('./controllers/rank-edit.controller');
4018
4019},{"./controllers/index.controller":40,"./controllers/news.controller":41,"./controllers/rank-edit.controller":42,"./controllers/rank.controller":43,"./discipline.module":45}],45:[function(require,module,exports){
4020'use strict';
4021
4022require('../core/core');
4023require('../../modules/pagination/pagination');
4024require('../../modules/forms/forms');
4025require('../../modules/ui/events-calendar/events-calendar');
4026
4027require('../../models/discipline/rank');
4028require('../../models/discipline/rankSeason');
4029
4030require('../../helpers/show-modal-message/show-modal-message');
4031
4032require('../documents/documents.module');
4033
4034angular.module('far.discipline', [
4035	'ngTouch',
4036	'angularFileUpload',
4037	'ui.select',
4038	'ui.bootstrap',
4039	'dekky.pagination',
4040	'dekky.forms',
4041	'far.models.rank',
4042	'far.models.rankSeason',
4043	'far.core',
4044	'far.helpers.showModalMessage',
4045    'far.ui.eventsCalendar',
4046	'templates',
4047	'far.documents.search'
4048]).value('formsConfig', {
4049	theme: '/dekky.forms/themes/far'
4050});
4051
4052},{"../../helpers/show-modal-message/show-modal-message":167,"../../models/discipline/rank":197,"../../models/discipline/rankSeason":198,"../../modules/forms/forms":244,"../../modules/pagination/pagination":341,"../../modules/ui/events-calendar/events-calendar":344,"../core/core":38,"../documents/documents.module":46}],46:[function(require,module,exports){
4053require('../../models/discipline/discipline');
4054require('../../models/document/document');
4055
4056angular.module('far.documents.search', [
4057        'far.models.discipline',
4058        'far.models.document'
4059    ])
4060    .controller('DocumentsController', ["$log", "$http", "form", "formsUtils", "Document", "Discipline", function ($log, $http, form, formsUtils, Document, Discipline) {
4061        var vm = {
4062            progress: true,
4063            submitted: false,
4064	        filterShow: true,
4065            form: form('DocumentsForm'),
4066            model: {},
4067            result: {
4068                offset: 0,
4069                limit: 100,
4070                data: []
4071            },
4072            total: {
4073                count: 0,
4074                pages: null
4075            },
4076            fistload: true,
4077            submit: function (next) {
4078                if (vm.submitted) {
4079                    return false;
4080                }
4081
4082                if (!next) {
4083                    vm.result.offset = 0;
4084                    vm.result.data = [];
4085                    vm.total.count = 0;
4086                    vm.total.pages = null;
4087                }
4088
4089                var data = {};
4090                for (var key in vm.model) {
4091                    if (typeof vm.model[key] == 'object' && vm.model[key] !== null) {
4092                        switch (key) {
4093                            case 'year':
4094                                data[key] = vm.model[key].year;
4095                                break;
4096                            default:
4097                                data[key] = vm.model[key].id;
4098                                break;
4099                        }
4100                    }
4101                }
4102
4103                if (vm.model.hasOwnProperty('q')) {
4104                    data['q'] = vm.model['q'];
4105                }
4106                if(!window.location.href.includes('committee')){
4107                if(1 > Object.keys(data).length){
4108                    if('' !== window.location.hash){
4109                        try {
4110                            data = JSON.parse(decodeURIComponent(atob(window.location.hash.substring(1))));
4111                        } catch (exception){
4112
4113                        }
4114                    }
4115                }
4116                }
4117                this.data = data;
4118
4119                if(!window.location.href.includes('committee')) {
4120                    window.location.hash = btoa(encodeURIComponent(JSON.stringify(data)));
4121                }
4122
4123
4124                vm.submitted = true;
4125
4126                $http.get(Routing.generate('api_get_document_search', data)).then(function (response) {
4127                    vm.total.count = response.headers('X-Total-Count');
4128                    vm.total.pages = Math.ceil(vm.total.count / vm.result.limit);
4129
4130                    for (var id in response.data) {
4131                        response.data[id]['url'] = Routing.generate('document_download', {id: response.data[id].id});
4132                        response.data[id]['edit'] = Routing.generate('admin_document_edit', {id: response.data[id].id});
4133
4134                        vm.result.data.push(response.data[id]);
4135                    }
4136
4137                    vm.submitted = false;
4138                    vm.fistload = false;
4139                }, function errorCallback(response) {
4140                    $log.error(response);
4141
4142                    vm.submitted = false;
4143                });
4144            },
4145            next: function () {
4146                vm.result.offset += vm.result.limit;
4147
4148                vm.submit(true);
4149            },
4150            getTotalCount: function () {
4151                if (!vm.fistload) {
4152                    return formsUtils.numEnding(vm.total.count, ['Найден', 'Найдено', 'Найдено']) + ' ' + vm.total.count + ' ' + formsUtils.numEnding(vm.total.count, ['документ', 'документа', 'документов']);
4153                }
4154                return '';
4155            }
4156        };
4157
4158        if(!window.location.href.includes('committee')) {
4159            if ('' !== window.location.hash) {
4160                try {
4161                    data = JSON.parse(decodeURIComponent(atob(window.location.hash.substring(1))));
4162                    vm.submit();
4163                } catch (exception) {
4164
4165                }
4166            }
4167        }
4168
4169        vm.form
4170            .addField('disciplines', 'selectObject', {
4171                validators: {
4172                    required: false
4173                },
4174                options: {
4175                    defaultOption: 'Дисциплина',
4176                    class: 'form__item form__item_select width-170',
4177                    ngChange: function () {
4178
4179                    }
4180                },
4181                ngOptions: 'item as item.name for item in field.items track by item.id',
4182                label: null
4183            }, Discipline.list)
4184            .addField('types', 'selectObject', {
4185                validators: {
4186                    required: false
4187                },
4188                options: {
4189                    defaultOption: 'Тип документа',
4190                    class: 'form__item form__item_select width-220',
4191                    ngChange: function () {
4192
4193                    }
4194                },
4195                ngOptions: 'item as item.name for item in field.items track by item.id',
4196                label: null
4197            }, Document.types)
4198            .addField('kinds', 'selectObject', {
4199                validators: {
4200                    required: false
4201                },
4202                options: {
4203                    defaultOption: 'Вид деятельности',
4204                    class: 'form__item form__item_select width-170',
4205                    ngChange: function () {
4206
4207                    }
4208                },
4209                ngOptions: 'item as item.name for item in field.items track by item.id',
4210                label: null
4211            }, Document.kinds)
4212            .addField('new_committees', 'selectObject', {
4213                validators: {
4214                    required: false
4215                },
4216                options: {
4217                    defaultOption: 'Комитеты и комиссии (новое отображение)',
4218                    class: 'form__item form__item_select width-200',
4219                    ngChange: function () {
4220
4221                    }
4222                },
4223                ngOptions: 'item as item.name for item in field.items track by item.id',
4224                label: null
4225            }, Document.new_committees)
4226
4227            .addField('committees', 'selectObject', {
4228                validators: {
4229                    required: false
4230                },
4231                options: {
4232                    defaultOption: 'Комитеты и комиссии',
4233                    class: 'form__item form__item_select width-200',
4234                    ngChange: function () {
4235
4236                    }
4237                },
4238                ngOptions: 'item as item.name for item in field.items track by item.id',
4239                label: null
4240            }, Document.committees)
4241            .addField('years', 'selectObject', {
4242                validators: {
4243                    required: false
4244                },
4245                options: {
4246                    defaultOption: 'Год',
4247                    class: 'form__item form__item_select width-80',
4248                    ngChange: function () {
4249
4250                    }
4251                },
4252                ngOptions: 'item as item.year for item in field.items',
4253                label: null
4254            }, Document.years);
4255
4256        return vm;
4257    }]);
4258
4259},{"../../models/discipline/discipline":196,"../../models/document/document":199}],47:[function(require,module,exports){
4260/**
4261 * Created by phatbass on 2/9/16.
4262 */
4263
4264angular.module('far.educations')
4265    .controller('EducationGalleryEditController', ["educationGalleryForm", "$http", "$log", "showModalMessage", function (educationGalleryForm, $http, $log, showModalMessage) {
4266        var errorMessages = [];
4267        
4268        var vm = {
4269            progress: true,
4270            submitted: false,
4271            fields: educationGalleryForm,
4272            form: {
4273                id: null,
4274                slides_files: []
4275            },
4276            construct: function (event) {
4277                vm.form.id = event;
4278
4279                $http.get(Routing.generate('api_event_get_event_gallery_edit', {event: vm.form.id}))
4280                    .then(function (response) {
4281                        angular.forEach(response.data, function (image) {
4282                            vm.form.slides_files.push(image);
4283                        });
4284
4285                        vm.progress = false;
4286                    }, function errorCallback(response) {
4287                        $log.error(response);
4288                        showModalMessage('Невозможно загрузить галерею.');
4289
4290                        vm.progress = false;
4291                    });
4292
4293                vm.fields.$fields.slides_files.uploader.onSuccessItem = function (item, response) {
4294                    vm.form.slides_files.push(response);
4295                };
4296                vm.fields.$fields.slides_files.uploader.onWhenAddingFileFailed = function(item, filter) {
4297                    var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
4298                    
4299                    if (errorMessages.indexOf(message) == -1) {
4300                        errorMessages.push(message); 
4301                    }
4302                };
4303                vm.fields.$fields.slides_files.uploader.onErrorItem = function() {
4304                    var message = 'Невозможно загрузить файл на сервер';
4305
4306                    if (errorMessages.indexOf(message) == -1) {
4307                        errorMessages.push(message);
4308                    }
4309                };
4310                vm.fields.$fields.slides_files.uploader.onCompleteAll = function() {
4311                    if (errorMessages.length > 0) {
4312                        showModalMessage(errorMessages.slice(0), 'Некоторые файлы не были загружены, т.к.:');
4313                        errorMessages = [];
4314                    }
4315                };
4316            },
4317            submit: function () {
4318                if (vm.submitted) {
4319                    return false;
4320                }
4321
4322                vm.submitted = true;
4323
4324                vm.form.slides_files = vm.form.slides_files.map(function (slide, index) {
4325                    slide.sort = index + 1;
4326                    return slide;
4327                });
4328
4329                $http.put(Routing.generate('api_event_put_event_gallery', {event: vm.form.id}), vm.form)
4330                    .then(function (response) {
4331                        document.location.href=Routing.generate('event_gallery', {id: response.data.id});
4332                    }, function errorCallback(response) {
4333                        $log.error(response);
4334
4335                        showModalMessage('Невозможно сохранить галерею.');
4336
4337                        vm.submitted = true;
4338                    });
4339            }
4340        };
4341
4342        return vm;
4343    }]);
4344
4345},{}],48:[function(require,module,exports){
4346'use strict';
4347
4348angular.module('far.educations')
4349    .controller('EducationGalleryViewController', ["$log", "$http", "$scope", "showModalMessage", "$uibModal", function ($log, $http, $scope, showModalMessage, $uibModal) {
4350        var vm = {
4351            progress: true,
4352            form: {
4353                id: null,
4354                slides_files: []
4355            },
4356            construct: function (event) {
4357                vm.form.id = event;
4358
4359                $http.get(Routing.generate('api_event_get_event_gallery', {event: vm.form.id}))
4360                    .then(function (response) {
4361                        angular.forEach(response.data, function (image) {
4362                            vm.form.slides_files.push(image);
4363                        });
4364
4365                        vm.progress = false;
4366                    }, function errorCallback(response) {
4367                        $log.error(response);
4368                        showModalMessage('Невозможно загрузить галерею.');
4369
4370                        vm.progress = false;
4371                    });
4372            },
4373            openSlider: function (slide) {
4374                $uibModal.open({
4375                    templateUrl: '/modals/slider/slider.html',
4376                    controller: 'SliderController as slider',
4377                    resolve: {
4378                        slides: function () {
4379                            return vm.form.slides_files;
4380                        },
4381                        selectedSlide: function () {
4382                            return slide;
4383                        }
4384                    }
4385                });
4386            },
4387            dragend: function () {
4388                vm.form.slides_files = vm.form.slides_files.map(function (slide, index) {
4389                    slide.sort = index + 1;
4390                    return slide;
4391                });
4392
4393                $http.put(Routing.generate('api_event_put_event_gallery', {event: vm.form.id}), vm.form)
4394                    .then(function (response) {
4395
4396                    }, function errorCallback(response) {
4397                        $log.error(response);
4398
4399                        showModalMessage('Невозможно сохранить галерею.');
4400
4401                        vm.submitted = true;
4402                    });
4403            }
4404        };
4405
4406        return vm;
4407    }]);
4408
4409},{}],49:[function(require,module,exports){
4410'use strict';
4411
4412angular.module('far.educations')
4413    .controller('EducationReportController', ["$window", "$log", "$scope", "$http", "$uibModal", "education", "educationReport", "educationReportForm", "FileUploader", function ($window, $log, $scope, $http, $uibModal, education, educationReport, educationReportForm, FileUploader) {
4414        var ascentRouteItems = {};
4415
4416        var vm = {
4417            progress: true,
4418            initEventReport: initEventReport,
4419            reportForm: educationReportForm,
4420            event: {},
4421            submit: submit,
4422            sendReport: sendReport,
4423            accepted: accepted,
4424            getDocumentUrl: getDocumentUrl,
4425            mountainFormAdd: mountainFormAdd
4426        };
4427
4428        vm.reportForm.$fields.club.uiSelectOptions.onSelect = function (item) {
4429            vm.event.event_education.club = item ? item : null;
4430        };
4431
4432        vm.reportForm.$fields.userChief.uiSelectOptions.onSelect = function (item, model, options) {
4433            vm.event.event_education.users.forEach(function (user, index) {
4434                if (user.uniqId === options.index) {
4435                    vm.event.event_education.users[index].user = model;
4436                }
4437            });
4438        };
4439        vm.reportForm.$fields.userCoach.uiSelectOptions.onSelect = function (item, model, options) {
4440            vm.event.event_education.users.forEach(function (user, index) {
4441                if (user.uniqId === options.index) {
4442                    vm.event.event_education.users[index].user = model;
4443                }
4444            });
4445        };
4446        vm.reportForm.$fields.userSafety.uiSelectOptions.onSelect = function (item, model, options) {
4447            vm.event.event_education.users.forEach(function (user, index) {
4448                if (user.uniqId === options.index) {
4449                    vm.event.event_education.users[index].user = model;
4450                }
4451            });
4452        };
4453
4454        vm.reportForm.$fields.countUsersTotal.options.class = 'form__item width-50';
4455        vm.reportForm.$fields.userInstructor.uiSelectOptions.onSelect = function (item, model, options) {
4456            vm.reportModel.updateUser(options.index, item);
4457        };
4458        vm.reportForm.$fields.userJuniorInstructor.uiSelectOptions.onSelect = function (item, model, options) {
4459            vm.reportModel.updateUser(options.index, item);
4460        };
4461        vm.reportForm.$fields.ascents.childForm.$fields.ascent_mountain_peak.uiSelectOptions.onSelect = function (item, model, options) {
4462            if (item && (angular.isUndefined(vm.reportModel.ascents[options.index].ascent_mountain_peak) || item.id != vm.reportModel.ascents[options.index].ascent_mountain_peak.id)) {
4463                vm.reportModel.ascents[options.index].ascent_mountain_peak = item;
4464                refreshMountainRouteAutoComplete(options.index);
4465            }
4466        };
4467        vm.reportForm.$fields.ascents.mountainFormAdd = mountainFormAdd;
4468        vm.reportForm.$fields.ascents.childForm.$fields.ascent_mountain_route.ngOptions = 'item as item.name  + " / " + item.mountain_route_complexity.name for item in field.getRouteItems(fieldIndex) track by item.id';
4469        vm.reportForm.$fields.ascents.childForm.$fields.ascent_mountain_route.getRouteItems = getRouteItems;
4470
4471        vm.reportForm.$fields.ascents.childForm.$fields.instructor.uiSelectOptions.onSelect = function (item, model, options) {
4472            if (item) {
4473                vm.reportModel.ascents[options.index].instructor = item;
4474            }
4475        };
4476        vm.reportForm.$fields.ascents.childForm.$fields.user_chief.uiSelectOptions.onSelect = function (item, model, options) {
4477            if (item) {
4478                vm.reportModel.ascents[options.index].user_chief = item;
4479            }
4480        };
4481
4482        function mountainFormAdd(index) {
4483            var modalInstance = $uibModal.open({
4484                templateUrl: '/modals/mountain-route-form/mountain-route-form.html',
4485                controller: 'MountainRouteFormController as routeForm',
4486                windowClass: 'modal-route',
4487                resolve: {
4488                    selectedPeak: function () {
4489                        return vm.reportModel.ascents[index].ascent_mountain_peak;
4490                    }
4491                }
4492            });
4493
4494            modalInstance.result.then(function (route) {
4495                vm.reportModel.ascents[index].ascent_mountain_route = route;
4496                vm.reportModel.ascents[index].ascent_mountain_peak = route.mountain_peaks[0];
4497                refreshMountainRouteAutoComplete(index);
4498            });
4499        }
4500
4501        function getRouteItems(index) {
4502            if (angular.isUndefined(ascentRouteItems[index])) {
4503                ascentRouteItems[index] = [];
4504            }
4505
4506            return ascentRouteItems[index];
4507        }
4508
4509        function refreshMountainRouteAutoComplete(index) {
4510            $http.get(Routing.generate('api_entities_get_mountainroutes', {
4511                offset: 0,
4512                limit: 100,
4513                peak_id: vm.reportModel.ascents[index].ascent_mountain_peak.id
4514            })).then(function (response) {
4515                angular.isUndefined(ascentRouteItems[index]) ?
4516                    ascentRouteItems[index] = [] :
4517                    ascentRouteItems[index].length = 0;
4518
4519                angular.forEach(response.data, function (route) {
4520                    ascentRouteItems[index].push(route[0]);
4521                });
4522            }).catch(function (response) {
4523                $log.error(response);
4524            });
4525        }
4526
4527        function initEventReport(eventId, eventReportEdit) {
4528            if (eventReportEdit) {
4529                vm.event = education.get(eventId, vm.eventUserTypes, function () {
4530                    vm.reportModel = educationReport.get(eventId, vm.eventUserTypes, function (report) {
4531                        report.ascents.forEach(function (ascent, index) {
4532                            ascent.ascent_mountain_peak = ascent.ascent_mountain_route.mountain_peaks[0];
4533                            refreshMountainRouteAutoComplete(index);
4534                        });
4535
4536                        if (vm.reportModel.documents_files.length > 0) {
4537                            vm.reportModel.documents_files.forEach(function (serverFile) {
4538                                var newFile = new FileUploader.FileItem(vm.reportForm.$fields.documentsFiles.uploader, {
4539                                    lastModifiedDate: new Date(),
4540                                    size: 1e6,
4541                                    name: serverFile.original_name
4542                                });
4543
4544                                newFile.progress = 100;
4545                                newFile.isUploaded = true;
4546                                newFile.isSuccess = true;
4547                                newFile.serverData = angular.merge({}, serverFile);
4548
4549                                vm.reportForm.$fields.documentsFiles.uploader.queue.push(newFile);
4550                            });
4551                        }
4552
4553                        vm.progress = false;
4554
4555                        if (vm.reportModel.users_complite) {
4556                            var users = [];
4557
4558                            vm.reportModel.users_complite.forEach(function(user) {
4559                                if ('user' in user) {
4560                                    users.push({fio:user.user.fio, email: user.user.email})
4561                                }
4562                            });
4563
4564                            vm.reportModel.users_complite = users;
4565                        }
4566
4567                    });
4568                });
4569            } else {
4570                vm.event = education.get(eventId, vm.eventUserTypes, function () {
4571                    vm.progress = false;
4572                });
4573
4574                vm.reportModel = educationReport.new({
4575                    event_id: eventId
4576                }, vm.eventUserTypes);
4577            }
4578        }
4579
4580        function getDocumentUrl(file_id) {
4581            return Routing.generate('api_upload_get_file', {fileStorage: file_id});
4582        }
4583
4584        function sendReport() {
4585            vm.reportModel.submitted = true;
4586            vm.reportModel.accepted = false;
4587
4588            submit();
4589        }
4590
4591        function accepted() {
4592            vm.reportModel.submitted = true;
4593            vm.reportModel.accepted = true;
4594
4595            submit();
4596        }
4597
4598        function submit() {
4599            console.log($scope.educationReportForm.$invalid);
4600
4601            if (vm.progress || $scope.educationReportForm.$invalid) {
4602                return;
4603            }
4604
4605            vm.progress = true;
4606
4607            // FIXME
4608            vm.reportModel.ascent_user_types = vm.ascent_user_types;
4609            vm.reportModel.eventUserTypes = vm.eventUserTypes;
4610
4611            vm.reportModel.event = {
4612                id: vm.event.id,
4613                description: vm.event.description,
4614                club: vm.event.event_education.club,
4615                users: vm.event.event_education.users
4616            };
4617
4618            vm.reportModel.documents_files = vm.documents_files;
4619
4620            //console.log(vm.reportModel.event);
4621
4622            vm.reportModel.save()
4623               .then(function (response) {
4624                    //$log.debug('ok!');
4625
4626                    $window.location.href = Routing.generate('event_view', {id: response.data.id});
4627               })
4628               .catch(function (response) {
4629                   $log.error(response);
4630
4631                   vm.progress = false;
4632               });
4633        }
4634
4635        window.educationReportController = vm;
4636
4637        return vm;
4638    }]);
4639
4640},{}],50:[function(require,module,exports){
4641'use strict';
4642
4643angular.module('far.educations').controller('EducationRequestController', ["$window", "$log", "$scope", "$rootScope", "$timeout", "education", "educationRequestForm", "mountainReg
4643ions", "FileUploader", "Geocoder", "maps", function ($window, $log, $scope, $rootScope, $timeout, education, educationRequestForm, mountainRegions, FileUploader, Geocoder, maps) {
4644    var geocoder = new Geocoder();
4645
4646    var vm = {
4647        progress: true,
4648        submitted: false,
4649        init: init,
4650        submit: submit,
4651        requestForm: educationRequestForm,
4652        form: {},
4653        club: {},
4654        eventType: null,
4655        getDocumentUrl: getDocumentUrl,
4656        accepted: function () {
4657            vm.form.event_education.accepted = vm.requestForm.$fields.accepted.items[1];
4658
4659            vm.submit();
4660        },
4661        reject: function () {
4662            vm.form.event_education.accepted = vm.requestForm.$fields.accepted.items[2];
4663
4664            vm.submit();
4665        },
4666        map: {
4667            center: maps.getDefaultCenter(),
4668            zoom: maps.getDefaultZoom(),
4669            markers: [],
4670            disableDefaultUI: true,
4671            scrollwheel: false,
4672            events: {
4673                click: function (map, eventName, event) {
4674                    var marker = geocoder.getLatLngObject(event[0].latLng);
4675                    marker.id = 1;
4676                    vm.map.markers = [marker];
4677                }
4678            }
4679        },
4680        changeDocument: function ($index, document) {
4681            if (!vm.form.event_education.documents[$index]) {
4682                vm.form.event_education.documents[$index] = document;
4683            } else {
4684                delete vm.form.event_application.documents[$index];
4685            }
4686        },
4687        updateName: function() {
4688            if (vm.form.event_education.club) {
4689                vm.form.name = 'Альпмероприятие ' + vm.form.event_education.club.name;
4690            }
4691        }
4692    };
4693
4694    vm.requestForm.$fields.club.uiSelectOptions.onSelect = function (item) {
4695        vm.form.event_education.club = item ? item : null;
4696        vm.updateName();
4697    };
4698    vm.requestForm.$fields.camp.uiSelectOptions.onSelect = function (item) {
4699        vm.form.camp = item ? item : null;
4700    };
4701    vm.requestForm.$fields.userChief.uiSelectOptions.onSelect = function (item, model, options) {
4702        vm.form.event_education.updateUser(options.index, item);
4703    };
4704    vm.requestForm.$fields.userCoach.uiSelectOptions.onSelect = function (item, model, options) {
4705        vm.form.event_education.updateUser(options.index, item);
4706    };
4707    vm.requestForm.$fields.userSafety.uiSelectOptions.onSelect = function (item, model, options) {
4708        vm.form.event_education.updateUser(options.index, item);
4709    };
4710    vm.requestForm.$fields.location.options.ngBlur = function changeLocation() {
4711        if (vm.form.location) {
4712            geocoder.getLocationsByAddress(vm.form.location).then(function (response) {
4713                var marker = {id: 1};
4714
4715                if (response.result.length > 0) {
4716                    vm.map.center = geocoder.getLatLngObject(response.result[0].geometry.location);
4717                    angular.merge(marker, geocoder.getLatLngObject(response.result[0].geometry.location));
4718                    vm.map.markers = [marker];
4719                }
4720            })
4721        }
4722    };
4723
4724    function init() {
4725        if (arguments.length > 0) {
4726            vm.form = education.get(arguments[0], vm.eventUserTypes, function () {
4727                if ( vm.form.event_education.documents_files.length > 0) {
4728                    vm.form.event_education.documents_files.forEach(function (serverFile) {
4729                        var newFile = new FileUploader.FileItem(vm.requestForm.$fields.documentsFiles.uploader, {
4730                            lastModifiedDate: new Date(),
4731                            size: 1e6,
4732                            name: serverFile.original_name
4733                        });
4734
4735                        newFile.progress = 100;
4736                        newFile.isUploaded = true;
4737                        newFile.isSuccess = true;
4738                        newFile.serverData = angular.merge({}, serverFile);
4739
4740                        vm.requestForm.$fields.documentsFiles.uploader.queue.push(newFile);
4741                    });
4742                }
4743
4744                if (vm.form.coordinates) {
4745                    vm.map.center = vm.form.coordinates;
4746                    vm.map.markers = [angular.merge({id: 1}, vm.form.coordinates)];
4747                }
4748
4749                if (Object.keys(vm.form.background_image).length) {
4750                    var backgroundImage = new FileUploader.FileItem(vm.requestForm.$fields.backgroundImage.uploader, {
4751                        lastModifiedDate: new Date(),
4752                        size: 1e6,
4753                        name: vm.form.background_image.image_name
4754                    });
4755
4756                    backgroundImage.progress = 100;
4757                    backgroundImage.isUploaded = true;
4758                    backgroundImage.isSuccess = true;
4759                    backgroundImage.serverData = angular.merge({}, vm.form.background_image);
4760
4761                    vm.requestForm.$fields.backgroundImage.uploader.queue.push(backgroundImage);
4762                }
4763
4764                vm.progress = false;
4765            });
4766        } else {
4767            vm.form = education.new({
4768                type: vm.eventType,
4769                disciplines: [],
4770                partners: []
4771            }, vm.eventUserTypes);
4772
4773            vm.form.event_education.club = vm.club;
4774            vm.updateName();
4775            vm.progress = false;
4776        }
4777    }
4778
4779    function getDocumentUrl(file_id) {
4780        return Routing.generate('api_upload_get_file', {fileStorage: file_id});
4781    }
4782
4783    function submit() {
4784        if (vm.submitted || $scope.educationRequestForm.$invalid) {
4785            return;
4786        }
4787
4788        vm.submitted = true;
4789        vm.progress = true;
4790
4791        if (!vm.form.event_education.accepted) {
4792            vm.form.event_education.accepted = vm.requestForm.$fields.accepted.items[0];
4793        }
4794
4795        if (vm.map.markers.length > 0) {
4796            vm.form.latitude = vm.map.markers[0].latitude;
4797            vm.form.longitude = vm.map.markers[0].longitude;
4798        }
4799
4800        vm.form.event_education.documents_files = vm.documents_files;
4801
4802        vm.form.save()
4803            .then(function (response) {
4804                if (response.data.id) {
4805                    $window.location.href = Routing.generate('event_view', {id: response.data.id});
4806                }
4807            }, function (response) {
4808                $log.error(response);
4809
4810                vm.submitted = false;
4811                vm.progress = false;
4812            });
4813    }
4814
4815    return vm;
4816}]);
4817
4818},{}],51:[function(require,module,exports){
4819/**
4820 * Created by phatbass on 2/9/16.
4821 */
4822
4823angular.module('far.educations')
4824    .controller('EducationUsersController', ["$log", "$scope", "$http", "$window", "form", "autocomplete", "formsUtils", "inviteUserForm", "http", function ($log, $scope, $http, $window, form, autocomplete, formsUtils, inviteUserForm, http) {
4825        var vm = {
4826            loaded: true,
4827            submitted: false,
4828            eventQualifications: [],
4829            eventUsersSearchModel: {},
4830            users: {
4831                offset: 0,
4832                limit: 500,
4833                data: [],
4834                id: {}
4835            },
4836            usersSelect: {},
4837            usersInvite: [],
4838            selectAll: false,
4839            selectAllFunc: function () {
4840                if (vm.selectAll) {
4841                    vm.usersSelect = angular.copy(vm.users.id);
4842                } else {
4843                    vm.usersSelect = {};
4844                }
4845            },
4846            total: {
4847                count: null,
4848                pages: null
4849            },
4850            eventUsersSearchForm: form('eventUsersSearchForm'),
4851            eventUsersInviteForm: form('eventUsersInviteForm'),
4852            search: function (next) {
4853                if ($scope.eventUsersSearchForm.$invalid || vm.submitted) {
4854                    return;
4855                }
4856
4857                if (!next) {
4858                    vm.users.offset = 0;
4859                    vm.users.data = [];
4860                    vm.total.count = null;
4861                    vm.total.pages = null;
4862                }
4863
4864                var data = angular.merge({}, vm.eventUsersSearchModel);
4865                data.member = +data.member;
4866                data['offset'] = vm.users.offset;
4867                data['limit'] = vm.users.limit;
4868
4869                vm.submitted = true;
4870
4871                vm.usersSelect = {};
4872
4873                $http.get(Routing.generate('api_event_event_users_search', data)).then(function (response) {
4874                    vm.total.count = response.headers('X-Total-Count');
4875                    vm.total.pages = Math.ceil(vm.total.count / vm.users.limit);
4876
4877                    for (var id in response.data) {
4878                        response.data[id]['url'] = Routing.generate('user_view', {userId: response.data[id].id});
4879
4880                        if (vm.eventQualifications.length) {
4881                            if (response.data[id].qualification) {
4882                                if (vm.eventQualifications.indexOf(response.data[id].qualification.id) != -1) {
4883                                    response.data[id]['show'] = true;
4884                                }
4885                            }
4886                        } else {
4887                            response.data[id]['show'] = true;
4888                        }
4889
4890                        vm.users.data.push(response.data[id]);
4891                        vm.users.id[id] = response.data[id].id;
4892                    }
4893
4894                    vm.submitted = false;
4895                }, function errorCallback(response) {
4896                    response = http.authenticationListener(response);
4897
4898                    $log.error(response);
4899
4900                    vm.submitted = false;
4901                });
4902            },
4903            add: function (id) {
4904                if (vm.submitted) {
4905                    return false;
4906                }
4907
4908                /*
4909                 if ( !$scope.membershipForm.$valid ) {
4910                 return false;
4911                 }
4912                 */
4913                vm.submitted = true;
4914
4915                $http.post(Routing.generate('api_event_post_event_users_add', {id: id}), {
4916                    event_users: vm.usersSelect,
4917                    users_invite: vm.usersInvite
4918                }).then(function (response) {
4919                    $window.location.reload(true);
4920                }, function errorCallback(response) {
4921                    response = http.authenticationListener(response);
4922
4923                    $log.error(response);
4924
4925                    vm.submitted = false;
4926                });
4927            },
4928            next: function () {
4929                vm.users.offset += vm.users.limit;
4930
4931                vm.submit(true);
4932            },
4933            getTotalCount: function () {
4934                return formsUtils.numEnding(vm.total.count, ['Найден', 'Найдено', 'Найдено']) + ' ' + vm.total.count + ' ' + formsUtils.numEnding(vm.total.count, ['человек', 'человека', 'человек']);
4935            }
4936        };
4937
4938        vm.eventUsersSearchForm
4939            .addField('user_city', 'uiSelect', {
4940                validators: {
4941                    required: false
4942                },
4943                options: {
4944                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
4945                    class: 'form__ui-select width-350'
4946                },
4947                uiSelectOptions: {
4948                    matchTitle: '{{ $select.selected.name }} ',
4949                    choicesTitle: '{{ item.name }}',
4950                    match: {
4951                        placeholder: 'Город',
4952                        allowClear: true
4953                    },
4954                    choices: {
4955                        repeat: 'item in field.items track by item.id',
4956                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "UserCity", "user_city")',
4957                        refreshDelay: 0
4958                    },
4959                    refreshAutoComplete: autocomplete.refreshAutoComplete,
4960                    onSelect: function (item) {
4961                        if (item) {
4962                            vm.eventUsersSearchModel.user_city = item.name;
4963                        }
4964                    }
4965                }
4966            }, autocomplete.get('user_city'))
4967            .addField('club', 'uiSelect', {
4968                validators: {
4969                    required: false
4970                },
4971                options: {
4972                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
4973                    class: 'form__ui-select width-450'
4974                },
4975                uiSelectOptions: {
4976                    matchTitle: '{{ $select.selected.name }} ',
4977                    choicesTitle: '{{ item.name }}',
4978                    match: {
4979                        placeholder: 'Федерация/Клуб',
4980                        allowClear: true
4981                    },
4982                    choices: {
4983                        repeat: 'item in field.items track by item.id',
4984                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Club", "club")',
4985                        refreshDelay: 0
4986                    },
4987                    refreshAutoComplete: autocomplete.refreshAutoComplete,
4988                    onSelect: function (item) {
4989                        vm.eventUsersSearchModel.club = item.id;
4990                    }
4991                }
4992            }, autocomplete.get('club'))
4993            .addField('member', 'checkbox', {
4994                validators: {
4995                    required: false
4996                },
4997
4998                label: 'Члены ФАР'
4999            })
5000            .addField('q', 'text', {
5001                validators: {
5002                    required: false
5003                },
5004                options: {
5005                    placeholder: 'Имя, фамилия, отчество',
5006                    class: 'form__item width-450'
5007                }
5008            })
5009        ;
5010
5011        vm.eventUsersInviteForm
5012            .addField('users_invite', 'collection', {
5013                validators: {
5014                    required: false
5015                },
5016                label: 'Пригласить участника',
5017                buttons: {
5018                    add: 'Пригласить участника',
5019                    remove: 'Удалить участника'
5020                }
5021            }, inviteUserForm)
5022        ;
5023
5024        return vm;
5025    }]);
5026
5027},{}],52:[function(require,module,exports){
5028require('../../models/education/educationDiscipline');
5029require('../../modules/pagination/pagination');
5030require('../../modules/maps/maps');
5031
5032angular.module('far.educations.search', [
5033        'dekky.pagination',
5034        'far.models.education.discipline',
5035        'far.maps'
5036    ])
5037    .controller('EducationsSearchController', ["$log", "$http", "$window", "$timeout", "$q", "pagination", "educationDiscipline", "uiGmapGoogleMapApi", "maps", function ($log,
5038                                                    $http,
5039                                                    $window,
5040                                                    $timeout,
5041                                                    $q,
5042                                                    pagination,
5043                                                        educationDiscipline,
5044                                                    uiGmapGoogleMapApi,
5045                                                    maps) {
5046        var googleMaps,
5047            itemsOnList = 3,
5048            itemsOnMap = 1000;
5049
5050        var vm = {
5051            constructor: constructor,
5052            pagination: pagination('events', {next: nextPage, itemsOnPage: itemsOnMap}),
5053            type: 3,
5054            disciplines: educationDiscipline.list,
5055            filters: {
5056                period: 'all',
5057                dateFrom: undefined,
5058                dateTo: undefined,
5059                disciplines: [],
5060                eventData: {
5061                    application: {
5062                        value: true,
5063                        disabled: false
5064                    },
5065                    education: {
5066                        value: false,
5067                        disabled: true
5068                    },
5069                    competition: {
5070                        value: true,
5071                        memory: null,
5072                        disabled: false
5073                    }
5074                }
5075            },
5076            applyFilters: applyFilters,
5077            showFilters: false,
5078            map: {
5079                center: maps.getDefaultCenter(),
5080                zoom: maps.getDefaultZoom(),
5081                disableDefaultUI: true,
5082                options: {
5083                    maxZoom: 12,
5084                    disableDefaultUI: true,
5085                    zoomControl: true,
5086                    scrollwheel: false,
5087                    styles: maps.getStyle()
5088                },
5089                markerEvents: {
5090                    click: function (marker, event, item) {
5091                        var infoWindow = getInfoWindow(item);
5092
5093                        for (var iw in vm.map.infoWindows) {
5094                            vm.map.infoWindows[iw].close();
5095                        }
5096
5097                        infoWindow.open(marker.map, marker);
5098                    }
5099                },
5100                infoWindows: {}
5101            },
5102            modal_choose: false,
5103            whatShow: 'map',
5104            showMap: showMap,
5105            showList: showList,
5106            eventRequest: function () {
5107                $window.location.href = Routing.generate('event_request', {type: vm.eventType});
5108            },
5109            changePeriod: function () {
5110                if (vm.filters.period == 'all_year_round') {
5111                    if (vm.filters.eventData.competition.value) {
5112                        vm.filters.eventData.competition.memory = true;
5113                    } else {
5114                        vm.filters.eventData.competition.memory = null;
5115                    }
5116
5117                    vm.filters.eventData.competition.value = false;
5118                    vm.filters.eventData.competition.disabled = true;
5119                } else {
5120                    if (vm.filters.eventData.competition.memory) {
5121                        vm.filters.eventData.competition.value = true;
5122                    }
5123
5124                    vm.filters.eventData.competition.memory = null;
5125                    vm.filters.eventData.competition.disabled = false;
5126                }
5127            }
5128        };
5129
5130        uiGmapGoogleMapApi.then(function (maps) {
5131            googleMaps = maps;
5132        });
5133
5134        function constructor(userId, type) {
5135            vm.userId = userId;
5136            vm.type = type;
5137        }
5138
5139        function showMap() {
5140            vm.whatShow = 'map';
5141            vm.pagination.changeItemsOnPage(itemsOnMap);
5142        }
5143
5144        function showList() {
5145            vm.whatShow = 'list';
5146            vm.pagination.changeItemsOnPage(itemsOnList);
5147        }
5148
5149        function applyFilters() {
5150            vm.filters.disciplines = vm.disciplines.filter(function (discipline) {
5151                return discipline.selected;
5152            }).map(function (discipline) {
5153                return discipline.id;
5154            });
5155
5156            vm.pagination.clear();
5157        }
5158
5159        function getInfoWindow(item) {
5160            if (!vm.map.infoWindows[item.id]) {
5161                vm.map.infoWindows[item.id] = new googleMaps.InfoWindow({
5162                    content:
5163                        '<div class="map-info-window">' +
5164                            '<p class="content__date">
5164' + ((item.all_year_round) ? 'Круглогодично': item.dates) +'</p>' +
5165                            '<h4>' + item.name + '</h4>' +
5166                            '<p><a href="' + item.event_url + '" class="btn-link" target="_blank">Подробнее</a></p>' +
5167                        '</div>'
5168                });
5169            }
5170
5171            return vm.map.infoWindows[item.id];
5172        }
5173
5174        function nextPage(page, count) {
5175            var data = {
5176                event_data: {},
5177                type: vm.type,
5178                offset: (page - 1) * count,
5179                limit: count,
5180                period: vm.filters.period,
5181                disciplines: vm.filters.disciplines.join(','),
5182                date: {
5183                    from: null,
5184                    to: null
5185                }
5186            };
5187
5188            if (angular.isDate(vm.filters.dateFrom)) {
5189                data.date.from = [vm.filters.dateFrom.getFullYear(), (vm.filters.dateFrom.getMonth() + 1), vm.filters.dateFrom.getDate()].join('-');
5190            }
5191
5192            if (angular.isDate(vm.filters.dateTo)) {
5193                data.date.to = [vm.filters.dateTo.getFullYear(), (vm.filters.dateTo.getMonth() + 1), vm.filters.dateTo.getDate()].join('-');
5194            }
5195
5196            for (var eventDataKey in vm.filters.eventData) {
5197                data.event_data[eventDataKey] = +vm.filters.eventData[eventDataKey].value;
5198            }
5199
5200            return $http.get(Routing.generate('api_event_get_eventplans', data)).then(function (response) {
5201                var items = [];
5202                vm.totalPages = Math.ceil(response.headers('X-Total-Count') / count);
5203
5204                angular.forEach(response.data, function (item) {
5205                    item.markerOptions = {
5206                        clickable: true
5207                    };
5208                    item.map = {infoWindow: null};
5209
5210                    items.push(item);
5211                });
5212
5213                return items;
5214            }).catch(function (response) {
5215                $log.error(response);
5216                return $q.reject(response);
5217            });
5218        }
5219
5220        return vm;
5221    }]);
5222
5223},{"../../models/education/educationDiscipline":201,"../../modules/maps/maps":338,"../../modules/pagination/pagination":341}],53:[function(require,module,exports){
5224require('./educations.module.js');
5225require('./controllers/education-request.controller');
5226require('./controllers/education-report.controller');
5227require('./controllers/education-users.controller');
5228require('./controllers/education-gallery-edit.controller');
5229require('./controllers/education-gallery-view.controller');
5230
5231},{"./controllers/education-gallery-edit.controller":47,"./controllers/education-gallery-view.controller":48,"./controllers/education-report.controller":49,"./controllers/education-request.controller":50,"./controllers/education-users.controller":51,"./educations.module.js":54}],54:[function(require,module,exports){
5232'use strict';
5233
5234require('../core/core');
5235require('../../modules/forms/forms');
5236require('../../modules/maps/maps');
5237
5238require('../../models/mountains/regions');
5239
5240require('../../models/education/education');
5241require('../../models/education/educationReport');
5242
5243require('../../forms/themes/inviteUser/inviteUser.theme');
5244require('../../forms/themes/typeaheadUser/typeaheadUser.theme');
5245
5246require('../../forms/educationRequestForm');
5247require('../../forms/educationReportForm');
5248require('../../forms/educationGalleryForm');
5249require('../../forms/inviteUserForm');
5250
5251require('../../helpers/show-modal-message/show-modal-message');
5252
5253require('../fos_user/directives/unique-user');
5254
5255require('../../modals/mountain-route-form/mountain-route-form');
5256
5257require('./education-search.module');
5258require('../documents/documents.module');
5259
5260require('../../modals/slider/slider');
5261
5262angular.module('far.educations', [
5263	'ngTouch',
5264	'dndLists',
5265	'ngMessages',
5266	'angularFileUpload',
5267	'ui.select',
5268	'ui.bootstrap',
5269	'dekky.forms',
5270	'dekky.forms.themes.typeaheadUser',
5271	'far.models.mountains.regions',
5272	'far.models.education.education',
5273	'far.models.education.educationReport',
5274	'far.core',
5275	'far.maps',
5276	'far.forms.educationRequestForm',
5277	'far.forms.educationReportForm',
5278	'far.forms.educationGalleryForm',
5279	'far.modals.mountain-route-form',
5280	'templates',
5281    'far.forms.inviteUserForm',
5282    'dekky.forms.themes.inviteUser',
5283    'far.helpers.showModalMessage',
5284    'far.fos_user.uniqueUser',
5285	'far.educations.search',
5286	'far.documents.search',
5287	'far.modals.slider'
5288]).value('formsConfig', {
5289	theme: '/dekky.forms/themes/far'
5290}).run(["$templateCache", function($templateCache) {
5291	$templateCache.put('/far.educations/fields/partnersCollection.html',
5292		'<div ng-init="model = model || []" ng-model="model">' +
5293			'<div repeat-collection ng-init="fieldIndex = $index" ng-form="childForm">' +
5294				'<div class="form-group right">' +
5295					'<button class="btn-gold" type="button" ng-click="field.doDelete(item, model, $index)">{{ field.buttons.remove }}</button>' +
5296				'</div>' +
5297				'<form-row ng-model="item.name" field="field.childForm.$fields.name" field-index="fieldIndex"></form-row>' +
5298				'<p class="form__error" role="alert" ng-if="childForm.$$parentForm.$submitted && childForm.name.$error.required">Обязательное поле</p>' +
5299				'<form-row ng-model="item.url" field="field.childForm.$fields.url" field-index="fieldIndex"></form-row>' +
5300				'<p class="form__error" role="alert" ng-if="childForm.$$parentForm.$submitted" ng-messages="childForm.url.$error">' +
5301					'<span ng-message="required">Обязательное поле</span>' +
5302					'<span ng-message="url">Урл в неверном формате</span>' +
5303				'</p>' +
5304				'<form-row ng-model="item.logo" field="field.childForm.$fields.logo" field-index="fieldIndex"></form-row>' +
5305				'<div class="form__line"></div>' +
5306			'</div>' +
5307
5308			'<div class="form-group">' +
5309				'<button class="btn-standart" type="button" ng-click="field.addItem(model)">{{ field.buttons.add }}
5309</button>' +
5310			'</div>' +
5311		'</div>'
5312	);
5313
5314	$templateCache.put('/far.educations/fields/ascentCollection.html',
5315		'<div ng-init="model = model || []" ng-model="model">' +
5316			'<div class="page-item" repeat-collection>' +
5317				'<div class="page-spoiler" ng-class="{\'page-spoiler_active\': showFormAscent}" ng-click="showFormAscent = !showFormAscent" ng-init="showFormAscent = true">Восхождение {{ $index + 1 }}</div>' +
5318				'<div ng-hide="!showFormAscent">' +
5319					'<form-row ng-model="item.ascent_date" field="field.childForm.$fields.ascent_date"></form-row>' +
5320					'<form-widget ng-model="item.ascent_mountain_peak" field="field.childForm.$fields.ascent_mountain_peak" ng-model-options="{ index: $index }"></form-widget>' +
5321					'<div class="form-group margin_b_30">' +
5322						'<form-widget ng-model="item.ascent_mountain_route" field="field.childForm.$fields.ascent_mountain_route" field-index="$index"></form-widget>' +
5323						'<p class="form__description width-200">Если пройденного маршрута нет в базе, оставьте заявку на добавление нового маршрута перейдя по ссылке.</p>' +
5324						'<a href="#" ng-click="field.mountainFormAdd($index)" class="btn-link">Добавить новый маршрут</a>' +
5325					'</div>' +
5326					'<div class="form-group margin_b_30">' +
5327						'<form-widget ng-model="item.ascent_type" field="field.childForm.$fields.ascent_type"></form-widget>' +
5328					'</div>' +
5329                    '<form-widget ng-model="item.instructor" field="field.childForm.$fields.instructor" ng-model-options="{ index: $index }"></form-widget>' +
5330					'<form-widget ng-model="item.user_chief" field="field.childForm.$fields.user_chief" ng-model-options="{ index: $index }"></form-widget>' +
5331					'<form-widget ng-model="item.users" field="field.childForm.$fields.ascent_users" template-url="/far.educations/fields/ascentUsersCollection.html"></form-widget>' +
5332					'<button class="btn-gold" type="button" ng-click="field.doDelete(item, model, $index)">{{ field.buttons.remove }}</button>' +
5333                    '<button class="btn-gold" style="margin-left: 2em;" type="button" onclick="window.educationReportController.submit()">{{ field.buttons.save }}</button>' +
5334					'<div class="form__line"></div>' +
5335				'</div>' +
5336			'</div>' +
5337
5338			'<a href="" ng-click="field.addItem(model)" class="btn-standart">Добавить восхождение</a>' +
5339		'</div>'
5340	);
5341
5342	$templateCache.put('/far.educations/fields/ascentUsersCollection.html',
5343		[
5344            '<div ng-init="model = model || []" ng-model="model">',
5345            	'<div repeat-collection>',
5346            		'<div class="form-group right">',
5347            			'<button class="btn-gold" type="button" ng-click="field.doDelete(item, model, $index)">{{ field.buttons.remove }}</button>',
5348            		'</div>',
5349            		'<div class="form__ui-typeahead width-350">',
5350            			'<form-widget field="field.childForm.$fields.fio" ng-model="item.fio" field-data="item"></form-widget>',
5351            		'</div>',
5352            		'<form-widget field="field.childForm.$fields.email" ng-model="item.email"></form-widget>',
5353            	'</div>',
5354            	'<span ng-click="field.addItem(model)" class="btn-link margin_b_40">Добавить участника</span>',
5355            '</div>'
5356		].join('')
5357	);
5358
5359    $templateCache.put('/far.educations/fields/compliteUsersCollection.html',
5360        [
5361            '<div ng-init="model = model || []" ng-model="model">',
5362            	'<div repeat-collection>',
5363            		'<div class="form-group right">',
5364            			'<button class="btn-gold" type="button" ng-click="field.doDelete(item, model, $index)">{{ field.buttons.remove }}</button>',
5365            		'</div>',
5366					'<div class="form__ui-typeahead width-350">',
5367						'<form-widget field="field.childForm.$fields.fio" ng-model="item.fio" field-data="item"></form-widget>',
5368					'</div>',
5369            		'<form-widget field="field.childForm.$fields.email" ng-model="item.email"></form-widget>',
5370            	'</div>',
5371				'<span ng-click="field.addItem(model)" class="btn-link margin_b_40">Добавить участника</span>',
5372            '</div>'
5373        ].join('')
5374    );
5375}]);
5376
5377},{"../../forms/educationGalleryForm":144,"../../forms/educationReportForm":145,"../../forms/educationRequestForm":146,"../../forms/inviteUserForm":151,"../../forms/themes/inviteUser/inviteUser.theme":163,"../../forms/themes/typeaheadUser/typeaheadUser.theme":164,"../../helpers/show-modal-message/show-modal-message":167,"../../modals/mountain-route-form/mountain-route-form":175,"../../modals/slider/slider":182,"../../models/education/education":200,"../../models/education/educationReport":203,"../../models/mountains/regions":214,"../../modules/forms/forms":244,"../../modules/maps/maps":338,"../core/core":38,"../documents/documents.module":46,"../fos_user/directives/unique-user":66,"./education-search.module":52}],55:[function(require,module,exports){
5378/**
5379 * Created by phatbass on 2/9/16.
5380 */
5381
5382angular.module('far.events')
5383    .controller('EventGalleryEditController', ["eventGalleryForm", "$http", "$log", "showModalMessage", function (eventGalleryForm, $http, $log, showModalMessage) {
5384        var errorMessages = [];
5385        
5386        var vm = {
5387            progress: true,
5388            submitted: false,
5389            fields: eventGalleryForm,
5390            form: {
5391                id: null,
5392                slides_files: []
5393            },
5394            construct: function (event) {
5395                vm.form.id = event;
5396
5397                $http.get(Routing.generate('api_event_get_event_gallery_edit', {event: vm.form.id}))
5398                    .then(function (response) {
5399                        angular.forEach(response.data, function (image) {
5400                            vm.form.slides_files.push(image);
5401                        });
5402
5403                        vm.progress = false;
5404                    }, function errorCallback(response) {
5405                        $log.error(response);
5406                        showModalMessage('Невозможно загрузить галерею.');
5407
5408                        vm.progress = false;
5409                    });
5410
5411                vm.fields.$fields.slides_files.uploader.onSuccessItem = function (item, response) {
5412                    vm.form.slides_files.push(response);
5413                };
5414                vm.fields.$fields.slides_files.uploader.onWhenAddingFileFailed = function(item, filter) {
5415                    var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
5416                    
5417                    if (errorMessages.indexOf(message) == -1) {
5418                        errorMessages.push(message); 
5419                    }
5420                };
5421                vm.fields.$fields.slides_files.uploader.onErrorItem = function() {
5422                    var message = 'Невозможно загрузить файл на сервер';
5423
5424                    if (errorMessages.indexOf(message) == -1) {
5425                        errorMessages.push(message);
5426                    }
5427                };
5428                vm.fields.$fields.slides_files.uploader.onCompleteAll = function() {
5429                    if (errorMessages.length > 0) {
5430                        showModalMessage(errorMessages.slice(0), 'Некоторые файлы не были загружены, т.к.:');
5431                        errorMessages = [];
5432                    }
5433                };
5434            },
5435            submit: function () {
5436                if (vm.submitted) {
5437                    return false;
5438                }
5439
5440                vm.submitted = true;
5441
5442                vm.form.slides_files = vm.form.slides_files.map(function (slide, index) {
5443                    slide.sort = index + 1;
5444                    return slide;
5445                });
5446
5447                $http.put(Routing.generate('api_event_put_event_gallery', {event: vm.form.id}), vm.form)
5448                    .then(function (response) {
5449                        document.location.href=Routing.generate('event_gallery', {id: response.data.id});
5450                    }, function errorCallback(response) {
5451                        $log.error(response);
5452
5453                        showModalMessage('Невозможно сохранить галерею.');
5454
5455                        vm.submitted = true;
5456                    });
5457            }
5458        };
5459
5460        return vm;
5461    }]);
5462
5463},{}],56:[function(require,module,exports){
5464'use strict';
5465
5466angular.module('far.events')
5467    .controller('EventGalleryViewController', ["$log", "$http", "$scope", "showModalMessage", "$uibModal", function ($log, $http, $scope, showModalMessage, $uibModal) {
5468        var vm = {
5469            progress: true,
5470            form: {
5471                id: null,
5472                slides_files: []
5473            },
5474            construct: function (event) {
5475                vm.form.id = event;
5476
5477                $http.get(Routing.generate('api_event_get_event_gallery', {event: vm.form.id}))
5478                    .then(function (response) {
5479                        angular.forEach(response.data, function (image) {
5480                            vm.form.slides_files.push(image);
5481                        });
5482
5483                        vm.progress = false;
5484                    }, function errorCallback(response) {
5485                        $log.error(response);
5486                        showModalMessage('Невозможно загрузить галерею.');
5487
5488                        vm.progress = false;
5489                    });
5490            },
5491            openSlider: function (slide) {
5492                $uibModal.open({
5493                    templateUrl: '/modals/slider/slider.html',
5494                    controller: 'SliderController as slider',
5495                    resolve: {
5496                        slides: function () {
5497                            return vm.form.slides_files;
5498                        },
5499                        selectedSlide: function () {
5500                            return slide;
5501                        }
5502                    }
5503                });
5504            },
5505            dragend: function () {
5506                vm.form.slides_files = vm.form.slides_files.map(function (slide, index) {
5507                    slide.sort = index + 1;
5508                    return slide;
5509                });
5510
5511                $http.put(Routing.generate('api_event_put_event_gallery', {event: vm.form.id}), vm.form)
5512                    .then(function (response) {
5513
5514                    }, function errorCallback(response) {
5515                        $log.error(response);
5516
5517                        showModalMessage('Невозможно сохранить галерею.');
5518
5519                        vm.submitted = true;
5520                    });
5521            }
5522        };
5523
5524        return vm;
5525    }]);
5526
5527},{}],57:[function(require,module,exports){
5528'use strict';
5529
5530angular.module('far.events')
5531    .controller('EventReportController', ["$window", "$log", "$scope", "$http", "$uibModal", "event", "eventReport", "eventReportForm", "FileUploader", function ($window, $log, $scope, $http, $uibModal, event, eventReport, eventReportForm, FileUploader) {
5532        var ascentRouteItems = {};
5533
5534        var vm = {
5535            progress: true,
5536            initEventReport: initEventReport,
5537            reportForm: eventReportForm,
5538            event: {},
5539            submit: submit,
5540            sendReport: sendReport,
5541            accepted: accepted,
5542            getDocumentUrl: getDocumentUrl,
5543            mountainFormAdd: mountainFormAdd,
5544            preCopyAscent: preCopyAscent,
5545            btn: {
5546                accepted: false,
5547                submitted: false
5548            }
5549        };
5550
5551        vm.reportForm.$fields.countUsersTotal.options.class = 'form__item width-50';
5552        vm.reportForm.$fields.countUsersCc.options.class = 'form__item width-50';
5553        vm.reportForm.$fields.countUsersCp.options.class = 'form__item width-50';
5554        vm.reportForm.$fields.countUsersNp.options.class = 'form__item width-50';
5555        vm.reportForm.$fields.countUsersCm.options.class = 'form__item width-50';
5556        vm.reportForm.$fields.userInstructor.uiSelectOptions.onSelect = function (item, model, options) {
5557            vm.reportModel.updateUser(options.index, item);
5558        };
5559        vm.reportForm.$fields.userJuniorInstructor.uiSelectOptions.onSelect = function (item, model, options) {
5560            vm.reportModel.updateUser(options.index, item);
5561        };
5562        vm.reportForm.$fields.ascents.childForm.$fields.ascent_mountain_peak.uiSelectOptions.onSelect = function (item, model, options) {
5563            if (item && (angular.isUndefined(vm.reportModel.ascents[options.index].ascent_mountain_peak) || item.id != vm.reportModel.ascents[options.index].ascent_mountain_peak.id)) {
5564                vm.reportModel.ascents[options.index].ascent_mountain_peak = item;
5565                refreshMountainRouteAutoComplete(options.index);
5566            }
5567        };
5568        vm.reportForm.$fields.ascents.mountainFormAdd = mountainFormAdd;
5569        vm.reportForm.$fields.ascents.childForm.$fields.ascent_mountain_route.ngOptions = 'item as item.name  + " / " + item.mountain_route_complexity.name for item in field.getRouteItems(fieldIndex) track by item.id';
5570        vm.reportForm.$fields.ascents.childForm.$fields.ascent_mountain_route.getRouteItems = getRouteItems;
5571        vm.reportForm.vm = vm;
5572        vm.reportForm.$fields.ascents.childForm.$fields.instructor.uiSelectOptions.onSelect = function (item, model, options) {
5573            if (item) {
5574                vm.reportModel.ascents[options.index].instructor = item;
5575            }
5576        };
5577        vm.reportForm.$fields.ascents.childForm.$fields.user_chief.uiSelectOptions.onSelect = function (item, model, options) {
5578            if (item) {
5579                vm.reportModel.ascents[options.index].user_chief = item;
5580            }
5581        };
5582
5583        function mountainFormAdd(index) {
5584            var modalInstance = $uibModal.open({
5585                templateUrl: '/modals/mountain-route-form/mountain-route-form.html',
5586                controller: 'MountainRouteFormController as routeForm',
5587                windowClass: 'modal-route',
5588                resolve: {
5589                    selectedPeak: function () {
5590                        return vm.reportModel.ascents[index].ascent_mountain_peak;
5591                    }
5592                }
5593            });
5594
5595            modalInstance.result.then(function (route) {
5596                vm.reportModel.ascents[index].ascent_mountain_route = route;
5597                vm.reportModel.ascents[index].ascent_mountain_peak = route.mountain_peaks[0];
5598                refreshMountainRouteAutoComplete(index);
5599            });
5600        }
5601
5602        function getRouteItems(index) {
5603            if (angular.isUndefined(ascentRouteItems[index])) {
5604                ascentRouteItems[index] = [];
5605            }
5606
5607            return ascentRouteItems[index];
5608        }
5609
5610        function preCopyAscent(index) {
5611            ascentRouteItems[vm.reportModel.ascents.length] = ascentRouteItems[index];
5612        }
5613
5614        function refreshMountainRouteAutoComplete(index) {
5615            $http.get(Routing.generate('api_entities_get_mountainroutes', {
5616                offset: 0,
5617                limit: 100,
5618                peak_id: vm.reportModel.ascents[index].ascent_mountain_peak.id
5619            })).then(function (response) {
5620                angular.isUndefined(ascentRouteItems[index]) ?
5621                    ascentRouteItems[index] = [] :
5622                    ascentRouteItems[index].length = 0;
5623
5624                angular.forEach(response.data, function (route) {
5625                    ascentRouteItems[index].push(route[0]);
5626                });
5627            }).catch(function (response) {
5628                $log.error(response);
5629            });
5630        }
5631
5632        function initEventReport(eventId, eventReportEdit) {
5633            if (eventReportEdit) {
5634                vm.event = event.get(eventId, vm.eventUserTypes, function () {
5635                    vm.reportModel = eventReport.get(eventId, vm.eventUserTypes, function (report) {
5636                        report.ascents.forEach(function (ascent, index) {
5637                            ascent.ascent_mountain_peak = ascent.ascent_mountain_route.mountain_peaks[0];
5638                            refreshMountainRouteAutoComplete(index);
5639                        });
5640
5641                        if (vm.reportModel.documents_files.length > 0) {
5642                            vm.reportModel.documents_files.forEach(function (serverFile) {
5643                                var newFile = new FileUploader.FileItem(vm.reportForm.$fields.documentsFiles.uploader, {
5644                                    lastModifiedDate: new Date(),
5645                                    size: 1e6,
5646                                    name: serverFile.original_name
5647                                });
5648
5649                                newFile.progress = 100;
5650                                newFile.isUploaded = true;
5651                                newFile.isSuccess = true;
5652                                newFile.serverData = angular.merge({}, serverFile);
5653
5654                                vm.reportForm.$fields.documentsFiles.uploader.queue.push(newFile);
5655                            });
5656                        }
5657
5658                        vm.btn.accepted = vm.reportModel.accepted;
5659                        vm.btn.submitted = vm.reportModel.submitted;
5660
5661                        vm.progress = false;
5662                    });
5663                });
5664            } else {
5665                vm.event = event.get(eventId, vm.eventUserTypes, function () {
5666                    vm.progress = false;
5667                });
5668
5669                vm.reportModel = eventReport.new({
5670                    event_id: eventId
5671                }, vm.eventUserTypes);
5672            }
5673        }
5674
5675        function getDocumentUrl(file_id) {
5676            return Routing.generate('api_upload_get_file', {fileStorage: file_id});
5677        }
5678
5679        function sendReport() {
5680            vm.reportModel.submitted = true;
5681            vm.reportModel.accepted = false;
5682
5683            $scope.eventReportForm.$submitted  = true;
5684
5685            submit();
5686        }
5687
5688        function accepted() {
5689            vm.reportModel.submitted = true;
5690            vm.reportModel.accepted = true;
5691
5692            $scope.eventReportForm.$submitted  = true;
5693
5694            submit();
5695        }
5696
5697        function submit() {
5698            if ((vm.reportModel.submitted || vm.reportModel.accepted) && (vm.progress || $scope.eventReportForm.$invali
5698d)) {
5699                return;
5700            }
5701
5702            vm.progress = true;
5703
5704            // FIXME
5705            vm.reportModel.ascent_user_types = vm.ascent_user_types;
5706            vm.reportModel.eventUserTypes = vm.eventUserTypes;
5707
5708            vm.reportModel.event = {
5709                id: vm.event.id,
5710                description: vm.event.description
5711            };
5712
5713            vm.reportModel.documents_files = vm.documents_files;
5714
5715            vm.reportModel.save()
5716                .then(function (response) {
5717                    //$log.debug('ok!');
5718
5719                    $window.location.href = Routing.generate('event_view', {id: response.data.id});
5720                })
5721                .catch(function (response) {
5722                    $log.error(response);
5723
5724                    vm.progress = false;
5725                });
5726        }
5727
5728        // sorry, не нашел другого способа добраться до контроллера из шаблона для коллекции восхождений
5729        window.eventReportController = vm;
5730
5731        return vm;
5732    }]);
5733
5734},{}],58:[function(require,module,exports){
5735'use strict';
5736
5737angular.module('far.events').controller('EventRequestController', ["$window", "$log", "$scope", "$rootScope", "$timeout", "event", "eventRequestForm", "mountainReg
5737ions", "FileUploader", "Geocoder", "maps", function ($window, $log, $scope, $rootScope, $timeout, event, eventRequestForm, mountainRegions, FileUploader, Geocoder, maps) {
5738    var geocoder = new Geocoder();
5739
5740    var vm = {
5741        progress: true,
5742        submitted: false,
5743        init: init,
5744        submit: submit,
5745        requestForm: eventRequestForm,
5746        form: {},
5747        club: {},
5748        eventType: null,
5749        getDocumentUrl: getDocumentUrl,
5750        accepted: function () {
5751            vm.form.event_application.accepted = vm.requestForm.$fields.accepted.items[1];
5752
5753            vm.submit();
5754        },
5755        reject: function () {
5756            vm.form.event_application.accepted = vm.requestForm.$fields.accepted.items[2];
5757
5758            vm.submit();
5759        },
5760        map: {
5761            center: maps.getDefaultCenter(),
5762            zoom: maps.getDefaultZoom(),
5763            markers: [],
5764            disableDefaultUI: true,
5765            scrollwheel: false,
5766            events: {
5767                click: function (map, eventName, event) {
5768                    var marker = geocoder.getLatLngObject(event[0].latLng);
5769                    marker.id = 1;
5770                    vm.map.markers = [marker];
5771                }
5772            }
5773        },
5774        changeDocument: function ($index, document) {
5775            if (!vm.form.event_application.documents[$index]) {
5776                vm.form.event_application.documents[$index] = document;
5777            } else {
5778                delete vm.form.event_application.documents[$index];
5779            }
5780        },
5781        updateName: function() {
5782            if (vm.form.event_application.club) {
5783                vm.form.name = 'Альпмероприятие ' + vm.form.event_application.club.name;
5784            }
5785        }
5786    };
5787
5788    vm.requestForm.$fields.club.uiSelectOptions.onSelect = function (item) {
5789        vm.form.event_application.club = item ? item : null;
5790        vm.updateName();
5791    };
5792    vm.requestForm.$fields.camp.uiSelectOptions.onSelect = function (item) {
5793        vm.form.camp = item ? item : null;
5794    };
5795
5796
5797    vm.requestForm.$fields.userChief.uiSelectOptions.onSelect = function (item, model, options) {
5798        vm.form.event_application.updateUser(options.index, item);
5799    };
5800    vm.requestForm.$fields.userCoach.uiSelectOptions.onSelect = function (item, model, options) {
5801        vm.form.event_application.updateUser(options.index, item);
5802    };
5803    vm.requestForm.$fields.userSafety.uiSelectOptions.onSelect = function (item, model, options) {
5804        vm.form.event_application.updateUser(options.index, item);
5805    };
5806    vm.requestForm.$fields.location.options.ngBlur = function changeLocation() {
5807        if (vm.form.location) {
5808            geocoder.getLocationsByAddress(vm.form.location).then(function (response) {
5809                var marker = {id: 1};
5810
5811                if (response.result.length > 0) {
5812                    vm.map.center = geocoder.getLatLngObject(response.result[0].geometry.location);
5813                    angular.merge(marker, geocoder.getLatLngObject(response.result[0].geometry.location));
5814                    vm.map.markers = [marker];
5815                }
5816            })
5817        }
5818    };
5819
5820    function init() {
5821        if (arguments.length > 0) {
5822            vm.form = event.get(arguments[0], vm.eventUserTypes, function () {
5823                if (vm.form.event_application.documents_files.length > 0) {
5824                    vm.form.event_application.documents_files.forEach(function (serverFile) {
5825                        var newFile = new FileUploader.FileItem(vm.requestForm.$fields.documentsFiles.uploader, {
5826                            lastModifiedDate: new Date(),
5827                            size: 1e6,
5828                            name: serverFile.original_name
5829                        });
5830                        vm.form.revisor=vm.revisor_id;
5831                        newFile.progress = 100;
5832                        newFile.isUploaded = true;
5833                        newFile.isSuccess = true;
5834                        newFile.serverData = angular.merge({}, serverFile);
5835
5836                        vm.requestForm.$fields.documentsFiles.uploader.queue.push(newFile);
5837                    });
5838                }
5839
5840                if (vm.form.coordinates) {
5841                    vm.map.center = vm.form.coordinates;
5842                    vm.map.markers = [angular.merge({id: 1}, vm.form.coordinates)];
5843                }
5844
5845                if (Object.keys(vm.form.background_image).length) {
5846                    var backgroundImage = new FileUploader.FileItem(vm.requestForm.$fields.backgroundImage.uploader, {
5847                        lastModifiedDate: new Date(),
5848                        size: 1e6,
5849                        name: vm.form.background_image.image_name
5850                    });
5851
5852                    backgroundImage.progress = 100;
5853                    backgroundImage.isUploaded = true;
5854                    backgroundImage.isSuccess = true;
5855                    backgroundImage.serverData = angular.merge({}, vm.form.background_image);
5856
5857                    vm.requestForm.$fields.backgroundImage.uploader.queue.push(backgroundImage);
5858                }
5859
5860                vm.progress = false;
5861            });
5862        } else {
5863            vm.form = event.new({
5864                type: vm.eventType,
5865                disciplines: [],
5866                partners: []
5867            }, vm.eventUserTypes);
5868
5869            vm.form.event_application.club = vm.club;
5870            vm.form.revisor_id=vm.revisor_id;
5871
5872            vm.updateName();
5873            vm.progress = false;
5874        }
5875    }
5876
5877    function getDocumentUrl(file_id) {
5878        return Routing.generate('api_upload_get_file', {fileStorage: file_id});
5879    }
5880
5881    function submit() {
5882        if (vm.submitted || $scope.eventRequestForm.$invalid) {
5883            console.error($scope.eventRequestForm);
5884
5885            return;
5886        }
5887
5888        vm.submitted = true;
5889        vm.progress = true;
5890
5891        if (!vm.form.event_application.accepted) {
5892            vm.form.event_application.accepted = vm.requestForm.$fields.accepted.items[0];
5893        }
5894
5895        if (vm.map.markers.length > 0) {
5896            vm.form.latitude = vm.map.markers[0].latitude;
5897            vm.form.longitude = vm.map.markers[0].longitude;
5898        }
5899
5900        vm.form.event_application.documents_files = vm.documents_files;
5901
5902        vm.form.save()
5903            .then(function (response) {
5904                if (response.data.id) {
5905                    $window.location.href = Routing.generate('event_view', {id: response.data.id});
5906                }
5907            }, function (response) {
5908                $log.error(response);
5909
5910                vm.submitted = false;
5911                vm.progress = false;
5912            });
5913    }
5914
5915    return vm;
5916}]);
5917
5918},{}],59:[function(require,module,exports){
5919/**
5920 * Created by phatbass on 2/9/16.
5921 */
5922
5923angular.module('far.events')
5924    .controller('EventUsersController', ["$log", "$scope", "$http", "$window", "form", "autocomplete", "formsUtils", "inviteUserForm", "http", function ($log, $scope, $http, $window, form, autocomplete, formsUtils, inviteUserForm, http) {
5925        var vm = {
5926            loaded: true,
5927            submitted: false,
5928            eventQualifications: [],
5929            eventUsersSearchModel: {},
5930            users: {
5931                offset: 0,
5932                limit: 500,
5933                data: [],
5934                id: {}
5935            },
5936            usersSelect: {},
5937            usersInvite: [],
5938            selectAll: false,
5939            selectAllFunc: function () {
5940                if (vm.selectAll) {
5941                    vm.usersSelect = angular.copy(vm.users.id);
5942                } else {
5943                    vm.usersSelect = {};
5944                }
5945            },
5946            total: {
5947                count: null,
5948                pages: null
5949            },
5950            eventUsersSearchForm: form('eventUsersSearchForm'),
5951            eventUsersInviteForm: form('eventUsersInviteForm'),
5952            search: function (next) {
5953                if ($scope.eventUsersSearchForm.$invalid || vm.submitted) {
5954                    return;
5955                }
5956
5957                if (!next) {
5958                    vm.users.offset = 0;
5959                    vm.users.data = [];
5960                    vm.total.count = null;
5961                    vm.total.pages = null;
5962                }
5963
5964                var data = angular.merge({}, vm.eventUsersSearchModel);
5965                data.member = +data.member;
5966                data['offset'] = vm.users.offset;
5967                data['limit'] = vm.users.limit;
5968
5969                vm.submitted = true;
5970
5971                vm.usersSelect = {};
5972
5973                $http.get(Routing.generate('api_event_event_users_search', data)).then(function (response) {
5974                    vm.total.count = response.headers('X-Total-Count');
5975                    vm.total.pages = Math.ceil(vm.total.count / vm.users.limit);
5976
5977                    for (var id in response.data) {
5978                        response.data[id]['url'] = Routing.generate('user_view', {userId: response.data[id].id});
5979
5980                        if (vm.eventQualifications.length) {
5981                            if (response.data[id].qualification) {
5982                                if (vm.eventQualifications.indexOf(response.data[id].qualification.id) != -1) {
5983                                    response.data[id]['show'] = true;
5984                                }
5985                            }
5986                        } else {
5987                            response.data[id]['show'] = true;
5988                        }
5989
5990                        vm.users.data.push(response.data[id]);
5991                        vm.users.id[id] = response.data[id].id;
5992                    }
5993
5994                    vm.submitted = false;
5995                }, function errorCallback(response) {
5996                    response = http.authenticationListener(response);
5997
5998                    $log.error(response);
5999
6000                    vm.submitted = false;
6001                });
6002            },
6003            add: function (id) {
6004                if (vm.submitted) {
6005                    return false;
6006                }
6007
6008                /*
6009                 if ( !$scope.membershipForm.$valid ) {
6010                 return false;
6011                 }
6012                 */
6013                vm.submitted = true;
6014
6015                $http.post(Routing.generate('api_event_post_event_users_add', {id: id}), {
6016                    event_users: vm.usersSelect,
6017                    users_invite: vm.usersInvite
6018                }).then(function (response) {
6019                    $window.location.reload(true);
6020                }, function errorCallback(response) {
6021                    response = http.authenticationListener(response);
6022
6023                    $log.error(response);
6024
6025                    vm.submitted = false;
6026                });
6027            },
6028            next: function () {
6029                vm.users.offset += vm.users.limit;
6030
6031                vm.submit(true);
6032            },
6033            getTotalCount: function () {
6034                return formsUtils.numEnding(vm.total.count, ['Найден', 'Найдено', 'Найдено']) + ' ' + vm.total.count + ' ' + formsUtils.numEnding(vm.total.count, ['человек', 'человека', 'человек']);
6035            }
6036        };
6037
6038        vm.eventUsersSearchForm
6039            .addField('user_city', 'uiSelect', {
6040                validators: {
6041                    required: false
6042                },
6043                options: {
6044                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
6045                    class: 'form__ui-select width-350'
6046                },
6047                uiSelectOptions: {
6048                    matchTitle: '{{ $select.selected.name }} ',
6049                    choicesTitle: '{{ item.name }}',
6050                    match: {
6051                        placeholder: 'Город',
6052                        allowClear: true
6053                    },
6054                    choices: {
6055                        repeat: 'item in field.items track by item.id',
6056                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "UserCity", "user_city")',
6057                        refreshDelay: 0
6058                    },
6059                    refreshAutoComplete: autocomplete.refreshAutoComplete,
6060                    onSelect: function (item) {
6061                        if (item) {
6062                            vm.eventUsersSearchModel.user_city = item.name;
6063                        }
6064                    }
6065                }
6066            }, autocomplete.get('user_city'))
6067            .addField('club', 'uiSelect', {
6068                validators: {
6069                    required: false
6070                },
6071                options: {
6072                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
6073                    class: 'form__ui-select width-450'
6074                },
6075                uiSelectOptions: {
6076                    matchTitle: '{{ $select.selected.name }} ',
6077                    choicesTitle: '{{ item.name }}',
6078                    match: {
6079                        placeholder: 'Федерация/Клуб',
6080                        allowClear: true
6081                    },
6082                    choices: {
6083                        repeat: 'item in field.items track by item.id',
6084                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Club", "club")',
6085                        refreshDelay: 0
6086                    },
6087                    refreshAutoComplete: autocomplete.refreshAutoComplete,
6088                    onSelect: function (item) {
6089                        vm.eventUsersSearchModel.club = item.id;
6090                    }
6091                }
6092            }, autocomplete.get('club'))
6093            .addField('member', 'checkbox', {
6094                validators: {
6095                    required: false
6096                },
6097
6098                label: 'Члены ФАР'
6099            })
6100            .addField('q', 'text', {
6101                validators: {
6102                    required: false
6103                },
6104                options: {
6105                    placeholder: 'Имя, фамилия, отчество',
6106                    class: 'form__item width-450'
6107                }
6108            })
6109        ;
6110
6111        vm.eventUsersInviteForm
6112            .addField('users_invite', 'collection', {
6113                validators: {
6114                    required: false
6115                },
6116                label: 'Пригласить участника',
6117                buttons: {
6118                    add: 'Пригласить участника',
6119                    remove: 'Удалить участника'
6120                }
6121            }, inviteUserForm)
6122        ;
6123
6124        return vm;
6125    }]);
6126
6127},{}],60:[function(require,module,exports){
6128require('../../models/event/eventDiscipline');
6129require('../../modules/pagination/pagination');
6130require('../../modules/maps/maps');
6131
6132angular.module('far.events.search', [
6133        'dekky.pagination',
6134        'far.models.event.discipline',
6135        'far.maps'
6136    ])
6137    .controller('EventsSearchController', ["$rootScope", "$log", "$http", "$window", "$timeout", "$q", "pagination", "eventDiscipline", "uiGmapGoogleMapApi", "maps", function (
6138                                                    $rootScope,
6139                                                    $log,
6140                                                    $http,
6141                                                    $window,
6142                                                    $timeout,
6143                                                    $q,
6144                                                    pagination,
6145                                                    eventDiscipline,
6146                                                    uiGmapGoogleMapApi,
6147                                                    maps) {
6148        var googleMaps,
6149            itemsOnList = 12,
6150            itemsOnMap = 1000;
6151
6152        var vm = {
6153            init: function(selectedDisciplineId) {
6154                if (selectedDisciplineId > 0) {
6155                    vm.selectedDisciplineId = selectedDisciplineId;
6156                    vm.filters.disciplines.push(selectedDisciplineId);
6157                    vm.filters.eventData.application.value = false;
6158                    vm.filters.eventData.education.value = false;
6159                    vm.filters.eventData.project.value = false;
6160                }
6161            },
6162            selectedDisciplineId: null,
6163            constructor: constructor,
6164            pagination: pagination('events', {next: nextPage, itemsOnPage: itemsOnMap}),
6165            type: 3,
6166            disciplines: eventDiscipline.list,
6167            filters: {
6168                period: 'all',
6169                dateFrom: undefined,
6170                dateTo: undefined,
6171                disciplines: [],
6172                eventData: {
6173                    application: {
6174                        value: true,
6175                        disabled: false
6176                    },
6177                    education: {
6178                        value: true,
6179                        disabled: false
6180                    },
6181                    competition: {
6182                        value: true,
6183                        memory: null,
6184                        disabled: false
6185                    },
6186                    project: {
6187                        value: true,
6188                        disabled: false
6189                    }
6190                }
6191            },
6192            applyFilters: applyFilters,
6193            showFilters: true,
6194            map: {
6195                center: maps.getDefaultCenter(),
6196                zoom: maps.getDefaultZoom(),
6197                disableDefaultUI: true,
6198                options: {
6199                    maxZoom: 12,
6200                    disableDefaultUI: true,
6201                    zoomControl: true,
6202                    scrollwheel: false,
6203                    styles: maps.getStyle()
6204                },
6205                markerEvents: {
6206                    click: function (marker, event, item) {
6207                        var infoWindow = getInfoWindow(item);
6208
6209                        for (var iw in vm.map.infoWindows) {
6210                            vm.map.infoWindows[iw].close();
6211                        }
6212
6213                        infoWindow.open(marker.map, marker);
6214                    }
6215                },
6216                infoWindows: {}
6217            },
6218            modal_choose: false,
6219            whatShow: 'map',
6220            showMap: showMap,
6221            showList: showList,
6222            showLast: showLast,
6223            showNear: showNear,
6224            eventRequest: function () {
6225                $window.location.href = Routing.generate('event_request', {type: vm.eventType});
6226            },
6227            changePeriod: function () {
6228                if (vm.filters.period == 'all_year_round') {
6229                    if (vm.filters.eventData.competition.value) {
6230                        vm.filters.eventData.competition.memory = true;
6231                    } else {
6232                        vm.filters.eventData.competition.memory = null;
6233                    }
6234
6235                    vm.filters.eventData.competition.value = false;
6236                    vm.filters.eventData.competition.disabled = true;
6237                } else {
6238                    if (vm.filters.eventData.competition.memory) {
6239                        vm.filters.eventData.competition.value = true;
6240                    }
6241
6242                    vm.filters.eventData.competition.memory = null;
6243                    vm.filters.eventData.competition.disabled = false;
6244                }
6245            },
6246            clearFilters: function () {
6247                vm.filters = {
6248                    period: 'all',
6249                    dateFrom: null,
6250                    dateTo: null,
6251                    disciplines: [],
6252                    eventData: {
6253                        application: {
6254                            value: true,
6255                            disabled: false
6256                        },
6257                        education: {
6258                            value: true,
6259                            disabled: false
6260                        },
6261                        competition: {
6262                            value: true,
6263                            memory: null,
6264                            disabled: false
6265                        },
6266                        project: {
6267                            value: true,
6268                            disabled: false
6269                        }
6270                    }
6271                };
6272
6273                angular.forEach(vm.disciplines, function(discipline) {
6274                    discipline.selected = false;
6275                });
6276
6277            }
6278        };
6279
6280        //После загрузки дисциплин помечаем выбранную ид которой приходит с url: /events/discipline-1
6281        $rootScope.$watch(function() {
6282            return vm.disciplines.length;
6283        }, function(length) {
6284            if (length > 0 && vm.selectedDisciplineId) {
6285                angular.forEach(vm.disciplines, function(discipline) {
6286                    if (discipline.id == vm.selectedDisciplineId) {
6287                        discipline.selected = true;
6288                    }
6289                });
6290            }
6291        });
6292
6293        uiGmapGoogleMapApi.then(function (maps) {
6294            googleMaps = maps;
6295        });
6296
6297        function constructor(userId, type) {
6298            vm.userId = userId;
6299            vm.type = type;
6300        }
6301
6302        function showMap() {
6303            vm.whatShow = 'map';
6304            vm.filters.dateLast = null;
6305            vm.filters.dateFrom = new Date('2000-01-01');
6306            vm.pagination.changeItemsOnPage(itemsOnMap);
6307        }
6308
6309        function showList() {
6310            vm.whatShow = 'list';
6311            vm.filters.dateLast = null;
6312            vm.filters.dateFrom = new Date('2000-01-01');
6313            vm.pagination.changeItemsOnPage(itemsOnList);
6314        }
6315
6316        function showLast() {
6317            vm.whatShow = 'last';
6318            vm.filters.dateLast = new Date();
6319            vm.filters.dateFrom = new Date('2000-01-01');
6320            vm.pagination.changeItemsOnPage(itemsOnList);
6321        }
6322
6323        function showNear() {
6324            vm.whatShow = 'near';
6325            vm.filters.dateLast = null;
6326            vm.filters.dateFrom = new Date();
6327            vm.pagination.changeItemsOnPage(itemsOnList);
6328        }
6329
6330        function applyFilters() {
6331            vm.filters.disciplines = vm.disciplines.filter(function (discipline) {
6332                return discipline.selected;
6333            }).map(function (discipline) {
6334                return discipline.id;
6335            });
6336
6337            vm.pagination.clear();
6338        }
6339
6340        function getInfoWindow(item) {
6341            if (!vm.map.infoWindows[item.id]) {
6342                vm.map.infoWindows[item.id] = new googleMaps.InfoWindow({
6343                    content:
6344                        '<div class="map-info-window">' +
6345                            '<p class="content__date">' + ((item.all_year_round) ? 'Круглогодично': item.dates) +'</p>' +
6346                            '<h4>' + item.name + '</h4>' +
6347                            '<p><a href="' + item.event_url + '" class="btn-link" target="_blank">Подробнее</a></p>' +
6348                        '</div>'
6349                });
6350            }
6351
6352            return vm.map.infoWindows[item.id];
6353        }
6354
6355        function nextPage(page, count) {
6356            var data = {
6357                event_data: {},
6358                type: vm.type,
6359                offset: (page - 1) * count,
6360                limit: count,
6361                period: vm.filters.period,
6362                disciplines: vm.filters.disciplines.join(','),
6363                date: {
6364                    from: null,
6365                    to: null,
6366                    last: null
6367                }
6368            };
6369
6370            if (angular.isDate(vm.filters.dateFrom)) {
6371                data.date.from = [vm.filters.dateFrom.getFullYear(), (vm.filters.dateFrom.getMonth() + 1), vm.filters.dateFrom.getDate()].join('-');
6372            }
6373
6374            if (angular.isDate(vm.filters.dateTo)) {
6375                data.date.to = [vm.filters.dateTo.getFullYear(), (vm.filters.dateTo.getMonth() + 1), vm.filters.dateTo.getDate()].join('-');
6376            }
6377
6378            if (angular.isDate(vm.filters.dateLast)) {
6379                data.date.last = [vm.filters.dateLast.getFullYear(), (vm.filters.dateLast.getMonth() + 1), vm.filters.dateLast.getDate()].join('-');
6380            }
6381
6382            for (var eventDataKey in vm.filters.eventData) {
6383                data.event_data[eventDataKey] = +vm.filters.eventData[eventDataKey].value;
6384            }
6385
6386            return $http.get(Routing.generate('api_event_get_eventplans', data)).then(function (response) {
6387                var items = [];
6388                vm.totalPages = Math.ceil(response.headers('X-Total-Count') / count);
6389
6390                angular.forEach(response.data, function (item) {
6391                    item.markerOptions = {
6392                        clickable: true
6393                    };
6394                    item.map = {infoWindow: null};
6395
6396                    items.push(item);
6397                });
6398
6399                return items;
6400            }).catch(function (response) {
6401                $log.error(response);
6402                return $q.reject(response);
6403            });
6404        }
6405
6406        return vm;
6407    }]);
6408
6409},{"../../models/event/eventDiscipline":206,"../../modules/maps/maps":338,"../../modules/pagination/pagination":341}],61:[function(require,module,exports){
6410require('./events.module.js');
6411require('./controllers/event-request.controller');
6412require('./controllers/event-report.controller');
6413require('./controllers/event-users.controller');
6414require('./controllers/event-gallery-edit.controller');
6415require('./controllers/event-gallery-view.controller');
6416
6417},{"./controllers/event-gallery-edit.controller":55,"./controllers/event-gallery-view.controller":56,"./controllers/event-report.controller":57,"./controllers/event-request.controller":58,"./controllers/event-users.controller":59,"./events.module.js":62}],62:[function(require,module,exports){
6418'use strict';
6419
6420require('../core/core');
6421require('../../modules/forms/forms');
6422require('../../modules/maps/maps');
6423
6424require('../../models/mountains/regions');
6425require('../../models/event/event');
6426require('../../models/event/eventReport');
6427
6428require('../../forms/themes/inviteUser/inviteUser.theme');
6429require('../../forms/themes/typeaheadUser/typeaheadUser.theme');
6430
6431require('../../forms/eventRequestForm');
6432require('../../forms/eventReportForm');
6433require('../../forms/eventGalleryForm');
6434require('../../forms/inviteUserForm');
6435
6436require('../../helpers/show-modal-message/show-modal-message');
6437
6438require('../fos_user/directives/unique-user');
6439
6440require('../../modals/mountain-route-form/mountain-route-form');
6441
6442require('./events-search.module');
6443require('../documents/documents.module');
6444
6445require('../../modals/slider/slider');
6446
6447angular.module('far.events', [
6448	'ngTouch',
6449	'dndLists',
6450	'ngMessages',
6451	'angularFileUpload',
6452	'ui.select',
6453	'ui.bootstrap',
6454	'dekky.forms',
6455	'dekky.forms.themes.typeaheadUser',
6456	'far.models.mountains.regions',
6457	'far.models.event.event',
6458	'far.models.event.eventReport',
6459	'far.core',
6460	'far.maps',
6461	'far.forms.eventRequestForm',
6462	'far.forms.eventReportForm',
6463	'far.forms.eventGalleryForm',
6464	'far.modals.mountain-route-form',
6465	'templates',
6466    'far.forms.inviteUserForm',
6467    'dekky.forms.themes.inviteUser',
6468    'far.helpers.showModalMessage',
6469    'far.fos_user.uniqueUser',
6470	'far.events.search',
6471	'far.documents.search',
6472	'far.modals.slider'
6473]).value('formsConfig', {
6474	theme: '/dekky.forms/themes/far'
6475}).run(["$templateCache", function($templateCache) {
6476	$templateCache.put('/far.events/fields/partnersCollection.html',
6477		'<div ng-init="model = model || []" ng-model="model">' +
6478			'<div repeat-collection ng-init="fieldIndex = $index" ng-form="childForm">' +
6479				'<div class="form-group right">' +
6480					'<button class="btn-gold" type="button" ng-click="field.doDelete(item, model, $index)">{{ field.buttons.remove }}</button>' +
6481				'</div>' +
6482				'<form-row ng-model="item.name" field="field.childForm.$fields.name" field-index="fieldIndex"></form-row>' +
6483				'<p class="form__error" role="alert" ng-if="childForm.$$parentForm.$submitted && childForm.name.$error.required">Обязательное поле</p>' +
6484				'<form-row ng-model="item.url" field="field.childForm.$fields.url" field-index="fieldIndex"></form-row>' +
6485				'<p class="form__error" role="alert" ng-if="childForm.$$parentForm.$submitted" ng-messages="childForm.url.$error">' +
6486					'<span ng-message="required">Обязательное поле</span>' +
6487					'<span ng-message="url">Урл в неверном формате</span>' +
6488				'</p>' +
6489				'<form-row ng-model="item.logo" field="field.childForm.$fields.logo" field-index="fieldIndex"></form-row>' +
6490				'<div class="form__line"></div>' +
6491			'</div>' +
6492
6493			'<div class="form-group">' +
6494				'<button class="btn-standart" type="button" ng-click="field.addItem(model)">{{ field.buttons.add }}</button>' +
6495			'</div>' +
6496		'</div>'
6497	);
6498
6499	$templateCache.put('/far.events/fields/ascentCollection.html',
6500		'<div ng-init="model = model || []" ng-model="model">' +
6501			'<div class="page-item" repeat-collection>' +
6502				'<div class="page-spoiler ascent-item" ng-class="{\'page-spoiler_active\': showFormAscent}" ng-click="showFormAscent = !showFormAscent" ng-init="showFormAscent = true">Восхождение {{ $index + 1 }}</div>' +
6503				'<div ng-hide="!showFormAscent">' +
6504					'<form-row ng-model="item.ascent_date" field="field.childForm.$fields.ascent_date"></form-row>' +
6505					'<form-widget ng-model="item.ascent_mountain_peak" field="field.childForm.$fields.ascent_mountain_peak" ng-model-options="{ index: $index }"></form-widget>' +
6506					'<div class="form-group">' +
6507						'<form-widget ng-model="item.ascent_mountain_route" field="field.childForm.$fields.ascent_mountain_route" field-index="$index"></form-widget>' +
6508						// '<p class="form__description width-200">Если пройденного маршрута нет в базе, оставьте заявку на добавление нового маршрута перейдя по ссылке.</p>' +
6509						// '<a href="#" ng-click="field.mountainFormAdd($index)" class="btn-link">Добавить новый маршрут</a>' +
6510					'</div>' +
6511					'<div class="form-group margin_b_30">' +
6512						'<form-widget ng-model="item.ascent_type" field="field.childForm.$fields.ascent_type"></form-widget>' +
6513					'</div>' +
6514                    '<form-widget ng-model="item.instructor" field="field.childForm.$fields.instructor" ng-model-options="{ index: $index }"></form-widget>' +
6515					'<form-widget ng-model="item.user_chief" field="field.childForm.$fields.user_chief" ng-model-options="{ index: $index }"></form-widget>' +
6516					'<form-widget ng-model="item.users" field="field.childForm.$fields.ascent_users" template-url="/far.events/fields/ascentUsersCollection.html"></form-widget>' +
6517					'<button class="btn-gold" type="button" ng-click="field.doDelete(item, model, $index)">{{ field.buttons.remove }}</button>' +
6518                    '<button style="margin-left: 2em;" class="btn-gold" type="button" onclick="window.eventReportController.submit()">{{ field.buttons.save }}</button>' +
6519					'<button style="margin-left: 2em;" class="btn-link btn-copy-item" type="button" ng-click="field.form.vm.preCopyAscent($index); field.copyItem(item, model, $index)">{{ field.buttons.copy }}</button>' +
6520					'<div class="form__line"></div>' +
6521				'</div>' +
6522			'</div>' +
6523
6524			'<a href="" ng-click="field.addItem(model)" class="btn-standart">Добавить восхождение</a>' +
6525		'</div>'
6526	);
6527
6528	$templateCache.put('/far.events/fields/ascentUsersCollection.html',
6529		'<div ng-init="model = model || []" ng-model="model">' +
6530			'<div repeat-collection>' +
6531				'<div class="form-group right">' +
6532					'<button class="btn-gold" type="button" ng-click="field.doDelete(item, model, $index)">{{ field.buttons.remove }}</button>' +
6533				'</div>' +
6534				'<div class="form__ui-typeahead width-350">' +
6535					'<form-widget field="field.childForm.$fields.fio" ng-model="item.fio" field-data="item"></form-widget>' +
6536				'</div>' +
6537				'<form-widget field="field.childForm.$fields.email" ng-model="item.email"></form-widget>' +
6538			'</div>' +
6539			'<span ng-click="field.addItem(model)" class="btn-link margin_b_40">Добавить участника</span>' +
6540		'</div>'
6541	);
6542}]);
6543
6544},{"../../forms/eventGalleryForm":147,"../../forms/eventReportForm":149,"../../forms/eventRequestForm":150,"../../forms/inviteUserForm":151,"../../forms/themes/inviteUser/inviteUser.theme":163,"../../forms/themes/typeaheadUser/typeaheadUser.theme":164,"../../helpers/show-modal-message/show-modal-message":167,"../../modals/mountain-route-form/mountain-route-form":175,"../../modals/slider/slider":182,"../../models/event/event":205,"../../models/event/eventReport":209,"../../models/mountains/regions":214,"../../modules/forms/forms":244,"../../modules/maps/maps":338,"../core/core":38,"../documents/documents.module":46,"../fos_user/directives/unique-user":66,"./events-search.module":60}],63:[function(require,module,exports){
6545/**
6546 * Created by phatbass on 2/9/16.
6547 */
6548
6549angular.module('far.fos_user')
6550    .controller('LoginController', ["hideShowPassword", function (hideShowPassword) {
6551        var vm = {
6552            hideShowPassword: hideShowPassword
6553        };
6554        return vm;
6555    }]);
6556
6557},{}],64:[function(require,module,exports){
6558/**
6559 * Created by phatbass on 2/9/16.
6560 */
6561
6562angular.module('far.fos_user')
6563    .controller('RegistrationController', ["$scope", "$log", "$http", "$window", "form", "hideShowPassword", "autocomplete", "showModalMessage", function ($scope, $log, $http, $window, form, hideShowPassword, autocomplete, showModalMessage) {
6564        var vm = {
6565            fast: true,
6566            submitted: false,
6567            errors: [],
6568            form: {},
6569            valid: {},
6570            blur: {
6571                phone: false,
6572                email: false,
6573                plainPassword: false,
6574                first_name: false,
6575                last_name: false,
6576                middle_name: false
6577            },
6578            name: '',
6579            noMiddleName: false,
6580            autoCompleteSelect: {
6581                country: null,
6582                region: null,
6583                city: null
6584            },
6585            formRegistration: form('formRegistration'),
6586            setName: function (value) {
6587                vm.name = value;
6588            },
6589            hideShowPassword: hideShowPassword,
6590            submit: function () {
6591                if ( vm.submitted ) {
6592                    return false;
6593                }
6594
6595                if ( !$scope.formRegistration.$valid ) {
6596                    Object.keys( vm.blur ).map(function( value ) {
6597                        vm.blur[ value ] = true;
6598                    });
6599
6600                    return false;
6601                }
6602
6603                vm.submitted = true;
6604
6605                var data = {};
6606
6607                data[vm.name] = angular.merge({}, vm.form);
6608
6609                if (angular.isObject(data[vm.name].city)) {
6610                    data[vm.name].city = data[vm.name].city.name;
6611                }
6612
6613                if (angular.isObject(data[vm.name].region)) {
6614                    data[vm.name].region = data[vm.name].region.name;
6615                }
6616
6617                $http.post(Routing.generate('fos_user_registration_register'), data)
6618                    .then(function successCallback() {
6619                        $window.location.href = Routing.generate('fos_user_registration_check_email');
6620                    }, function errorCallback(response) {
6621                        vm.errors = [];
6622
6623                        if (angular.isDefined(response.data.form) ) {
6624                            if (angular.isDefined(response.data.form.errors) ) {
6625                                response.data.form.errors.forEach(function (error) {
6626                                    vm.errors.push(error);
6627                                });
6628                            } else {
6629                                for ( var key in response.data.form.children ) {
6630                                    if ( response.data.form.children[key].errors ) {
6631                                        for ( var error in response.data.form.children[key].errors ) {
6632                                            vm.errors.push(response.data.form.children[key].errors[ error ]);
6633                                        }
6634                                    }
6635                                }
6636                            }
6637                        } else {
6638                            vm.errors.push('Ошибка на сервере. Попробуйте позже.');
6639                        }
6640
6641                        showModalMessage(vm.errors.join(", "));
6642
6643                        vm.submitted = false;
6644                    });
6645            }
6646        };
6647
6648        vm.formRegistration
6649            .addField('country', 'uiSelect', {
6650                validators: {
6651                    required: true
6652                },
6653                options: {
6654                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
6655                    class: 'form__ui-select width-350'
6656                },
6657                uiSelectOptions: {
6658                    matchTitle: '{{ $select.selected.name }} ',
6659                    choicesTitle: '{{ item.name }}',
6660                    match: {
6661                        placeholder: 'Страна',
6662                        allowClear: true
6663                    },
6664                    choices: {
6665                        repeat: 'item in field.items track by item.id',
6666                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Country", "country")',
6667                        refreshDelay: 0
6668                    },
6669                    refreshAutoComplete: autocomplete.refreshAutoComplete,
6670                    onSelect: function( item ) {
6671                        if ( item ) {
6672                            vm.autoCompleteSelect.country = item.id;
6673                            vm.autoCompleteSelect.region = null;
6674                            vm.autoCompleteSelect.city = null;
6675                            vm.form.country = item.id;
6676
6677                            vm.formRegistration.$fields.region.items = [];
6678                        }
6679                    }
6680                }
6681            }, autocomplete.get('country'))
6682            .addField('region', 'uiTypeahead', {
6683                validators: {
6684                    required: true
6685                },
6686                label: null,
6687                options: {
6688                    class: 'form__item',
6689                    placeholder: 'Регион',
6690                    tabindex: 10,
6691                    uibTypeahead: "row as row.name for row in field.refreshAutoComplete($viewValue, 'Region')"
6692                },
6693                fieldData: {
6694                    clearBtn: true,
6695                    refreshAutoComplete: function(name, term) {
6696                        return autocomplete.refreshAutoComplete(name, term, null, vm.autoCompleteSelect)
6697                    }
6698                }
6699            })
6700            .addField('city', 'uiTypeahead', {
6701                validators: {
6702                    required: true
6703                },
6704                label: null,
6705                options: {
6706                    class: 'form__item',
6707                    placeholder: 'Населенный пункт',
6708                    uibTypeahead: "row as row.name for row in field.refreshAutoComplete($viewValue, 'City')"
6709                },
6710                fieldData: {
6711                    clearBtn: true,
6712                    refreshAutoComplete: function(name, term) {
6713
6714                        if (angular.isObject(vm.form.region)) {
6715                            vm.autoCompleteSelect.region = vm.form.region.id;
6716                        } else {
6717                            vm.autoCompleteSelect.region = null;
6718                        }
6719
6720                        return autocomplete.refreshAutoComplete(name, term, null, vm.autoCompleteSelect)
6721                    }
6722                }
6723            })
6724            .addField('club', 'uiSelect', {
6725                validators: {
6726                    required: true
6727                },
6728                options: {
6729                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
6730                    class: 'form__ui-select width-350'
6731                },
6732                uiSelectOptions: {
6733                    matchTitle: '{{ $select.selected.name }} ',
6734                    choicesTitle: '{{ item.name }}',
6735                    match: {
6736                        placeholder: 'Выберите клуб',
6737                        allowClear: true
6738                    },
6739                    choices: {
6740                        repeat: 'item in field.items track by item.id',
6741                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Club", "club")',
6742                        refreshDelay: 0
6743                    },
6744                    refreshAutoComplete: autocomplete.refreshAutoComplete,
6745                    onSelect: function(item) {
6746                        vm.form.club = item ? item.id : null;
6747                    }
6748                }
6749            }, autocomplete.get('club'))
6750            .addField('middle_name', 'uiTypeahead', {
6751                validators: {
6752                    required: false
6753                },
6754                label: null,
6755                options: {
6756                    class: 'form__item',
6757                    placeholder: 'Отчество',
6758                    tabindex: 10,
6759                    uibTypeahead: "row as row.name for row in field.refreshAutoComplete($viewValue, 'MiddleName')"
6760                },
6761                fieldData: {
6762                    clearBtn: true,
6763                    refreshAutoComplete: function(name, term) {
6764                        return autocomplete.refreshAutoComplete(name, term, null, vm.autoCompleteSelect)
6765                    }
6766                }
6767            })
6768            .addField('no_middle_name', 'checkbox', {
6769                validators: {
6770                    required: false
6771                },
6772                options: {},
6773                label: 'Нет отчества'
6774            })
6775        ;
6776
6777        return vm;
6778    }]);
6779
6780},{}],65:[function(require,module,exports){
6781'use strict';
6782
6783angular.module('far.fos_user.uniquePhone', [])
6784.directive('uniquePhone', ["$log", "$http", "$q", function($log, $http, $q) {
6785	return {
6786		restrict: 'A',
6787		require: 'ngModel',
6788		link: function(scope, element, attr, ngController) {
6789			ngController.$asyncValidators.uniquePhone = function(modelValue, viewValue) {
6790				var value = modelValue || viewValue;
6791
6792				return $http.get(Routing.generate('api_entities_find_user', {phone: value})).
6793					then(function resolved() {
6794						return $q.reject('exists');
6795					}, function rejected() {
6796						return true;
6797					});
6798			}
6799		}
6800	};
6801}]);
6802
6803},{}],66:[function(require,module,exports){
6804'use strict';
6805
6806angular.module('far.fos_user.uniqueUser', [])
6807.directive('uniqueUser', ["$log", "$http", "$q", function($log, $http, $q) {
6808	return {
6809		restrict: 'A',
6810		require: 'ngModel',
6811		link: function(scope, element, attr, ngController) {
6812			ngController.$asyncValidators.uniqueUser = function(modelValue, viewValue) {
6813				var value = modelValue || viewValue;
6814
6815				return $http.get(Routing.generate('api_entities_find_user', {email: value})).
6816					then(function resolved() {
6817						return $q.reject('exists');
6818					}, function rejected() {
6819						return true;
6820					});
6821			}
6822		}
6823	};
6824}]);
6825
6826},{}],67:[function(require,module,exports){
6827require('./fos_user.module');
6828require('./controllers/login.controller');
6829require('./controllers/registration.controller');
6830
6831},{"./controllers/login.controller":63,"./controllers/registration.controller":64,"./fos_user.module":68}],68:[function(require,module,exports){
6832'use strict';
6833
6834require('../core/core');
6835require('../../modules/forms/forms');
6836require('./directives/unique-phone');
6837require('./directives/unique-user');
6838
6839require('../../helpers/show-modal-message/show-modal-message');
6840
6841angular.module('far.fos_user', [
6842    'ngMessages',
6843    'ui.bootstrap',
6844	'far.core',
6845    'dekky.forms',
6846    'far.fos_user.uniquePhone',
6847    'far.fos_user.uniqueUser',
6848    'far.helpers.showModalMessage'
6849])
6850.value('formsConfig', {
6851    theme: '/dekky.forms/themes/far'
6852});
6853
6854},{"../../helpers/show-modal-message/show-modal-message":167,"../../modules/forms/forms":244,"../core/core":38,"./directives/unique-phone":65,"./directives/unique-user":66}],69:[function(require,module,exports){
6855'use strict';
6856
6857angular.module('far.index')
6858    .controller('IndexViewController', ["$http", "$log", "formsUtils", function($http, $log, formsUtils) {
6859        $http.get(Routing.generate('api_event_get_event_project_homepage'))
6860            .then(function(response) {
6861                for(var key in response.data) {
6862                    var item = response.data[key];
6863
6864                    item.url = Routing.generate('event_view', {id: item.id});
6865
6866                    vm.projects.push(item)
6867                }
6868            })
6869            .catch(function(response) {
6870                $log.error(response);
6871            });
6872
6873        $http.get(Routing.generate('api_get_rubric_list'))
6874            .then(function(response) {
6875                for(var key in response.data) {
6876                    var item = response.data[key];
6877
6878                    item.url = Routing.generate('blog_rubric', {slug: item.slug});
6879                    if(item.posts_count > 0) {
6880                         item.posts_count = item.posts_count + ' ' + formsUtils.numEnding( item.posts_count, ['статья', 'статьи', 'статей'] );
6881                    } else {
6882                         item.posts_count = 0;
6883                    }
6884                    switch (item.slug) {
6885                        case 'putievoditiel-po-ghornym-raionam':
6886                            item.url = Routing.generate('mountains_routes_by_peak');
6887                            item.url_text = 'Перейти';
6888                            break;
6889                        case 'strakhovaniie-ekstriemal-nykh-vidov-sporta':
6890                            item.url = Routing.generate('insurance_index');
6891                            item.url_text = 'Перейти';
6892                            break;
6893                        case 'al-pinistskiie-kluby-v-rossii':
6894                            item.url = Routing.generate('search_alpclub');
6895                            item.url_text = 'Перейти';
6896                            break;
6897                        case 'al-pinistskiie-laghieria':
6898                            item.url = Routing.generate('search_camp');
6899                            item.url_text = 'Перейти';
6900                            break;
6901                        default:
6902                            item.url_text = 'Читать статьи';
6903                            break;
6904                    }
6905
6906                    vm.rubrics.push(item)
6907                }
6908            })
6909            .catch(function(response) {
6910                $log.error(response);
6911            });
6912
6913        $http.get(Routing.generate('api_get_homepage_post_list'))
6914            .then(function(response) {
6915                for(var key in response.data) {
6916                    var item = response.data[key];
6917                    item.url = Routing.generate('blog_post', {rubric: item.rubric.slug, post: item.slug});
6918
6919                    vm.posts.push(item)
6920                }
6921            })
6922            .catch(function(response) {
6923                $log.error(response);
6924            });
6925
6926        var vm = {
6927            projects: [],
6928            disciplines: [],
6929            rubrics: [],
6930	    posts: [],
6931            twoColumn: function (array, type) {
6932                var index = 0,
6933                    result = [];
6934
6935                for(var key in array) {
6936                    var item = array[key],
6937                        i = key % 2;
6938
6939                    switch (type) {
6940                        case 'project' :
6941                            item.url = Routing.generate('event_view', {id: item.id});
6942                            break;
6943                        case 'blog' :
6944                            item.url = Routing.generate('blog_post', {rubric: item.rubric.slug, post: item.slug});
6945                            item.posts_count = item.posts_count + ' ' + formsUtils.numEnding( item.posts_count, ['статья', 'статьи', 'статей'] );
6946                            break;
6947                    }
6948
6949
6950                    if (angular.isUndefined(result[index])) {
6951                        result[index] = [];
6952                    }
6953
6954                    result[index][i] = item;
6955
6956                    if (i) {
6957                        index++;
6958                    }
6959                }
6960
6961                return result;
6962            }
6963        };
6964
6965        return vm;
6966    }]);
6967
6968},{}],70:[function(require,module,exports){
6969require('./index.module');
6970require('./templates/carousel.html');
6971require('./templates/post.html');
6972require('./templates/rubric.html');
6973require('./templates/project.html');
6974require('./controllers/view.controller');
6975
6976},{"./controllers/view.controller":69,"./index.module":71,"./templates/carousel.html":72,"./templates/post.html":73,"./templates/project.html":74,"./templates/rubric.html":75}],71:[function(require,module,exports){
6977'use strict';
6978
6979require('../core/core');
6980require('../../modules/pagination/pagination');
6981require('../../modules/forms/forms');
6982require('../../modules/gallery/gallery');
6983require('../../modules/carousel/carousel');
6984
6985require('../../modals/slider/slider');
6986
6987require('../../helpers/show-modal-message/show-modal-message');
6988
6989require('../events/events-search.module');
6990
6991angular.module('far.index', [
6992	'ngTouch',
6993	'angularFileUpload',
6994	'ui.select',
6995	'ui.bootstrap',
6996	'dekky.pagination',
6997	'dekky.forms',
6998	'far.gallery',
6999    'far.carousel',
7000	'far.core',
7001	'far.modals.slider',
7002	'far.helpers.showModalMessage',
7003	'templates',
7004	'far.events.search'
7005]).value('formsConfig', {
7006	theme: '/dekky.forms/themes/far'
7007});
7008
7009},{"../../helpers/show-modal-message/show-modal-message":167,"../../modals/slider/slider":182,"../../modules/carousel/carousel":236,"../../modules/forms/forms":244,"../../modules/gallery/gallery":332,"../../modules/pagination/pagination":341,"../core/core":38,"../events/events-search.module":60}],72:[function(require,module,exports){
7010var ngModule;
7011try {
7012  ngModule = angular.module('templates');
7013} catch (e) {
7014  ngModule = angular.module('templates', []);
7015}
7016
7017ngModule.run(['$templateCache', function ($templateCache) {
7018  $templateCache.put('/app/index/templates/carousel.html',
7019    '<div ng-mouseenter="pause()" ng-mouseleave="play()" class="carousel" ng-swipe-right="prev()" ng-swipe-left="next()">\n' +
7020    '    <div class="carousel-inner" ng-transclude></div>\n' +
7021    '    <button class="arrow-left arrows" ng-click="prev()" ng-show="slides.length > 1"></button>\n' +
7022    '    <button class="arrow-right arrows right-ar" ng-click="next()" ng-show="slides.length > 1"></button>\n' +
7023    '</div>');
7024}]);
7025
7026module.exports = "/app/index/templates/carousel.html";
7027},{}],73:[function(require,module,exports){
7028var ngModule;
7029try {
7030  ngModule = angular.module('templates');
7031} catch (e) {
7032  ngModule = angular.module('templates', []);
7033}
7034
7035ngModule.run(['$templateCache', function ($templateCache) {
7036  $templateCache.put('/app/index/templates/post.html',
7037    '<ul>\n' +
7038    '    <li class="slide-projects" ng-repeat="item in items track by item.id">\n' +
7039    '        <div class="mosaic__item mosaic__item_two blog-slide">\n' +
7040    '            <div class="table__item artic-item">\n' +
7041    '                <div class="image__block">\n' +
7042    '                    <img class="table__img" src="{{ item.image.thumb_path }}">\n' +
7043    '                </div>\n' +
7044    '                <div class="text__block">\n' +
7045    '                    <p class="table__title artic-tet"><a href="{{ item.url }}">{{ item.name }}</a></p>\n' +
7046    '                    <p class="table__subtitle artic-sub">{{ item.description }}</p>\n' +
7047    '\n' +
7048    '                    <a href="/blog/{{ item.rubric.slug }}/" class="btn-link">{{ item.rubric.name }}</a> <br />\n' +
7049    '                    <div class="stats-preview">\n' +
7050    '                        <div class="likes-count stats-count">{{ item.likes ? item.likes : 0 }}</div>\n' +
7051    '                        <a href="{{ item.url }}#comments_title">\n' +
7052    '                            <div class="comments-count" ng-show="item.comments > 0">{{ item.comments }}</div>\n' +
7053    '                        </a>\n' +
7054    '                        <div class="views-count" ng-show="item.viewed > 0">{{ item.viewed }}</div>\n' +
7055    '                    </div>\n' +
7056    '                </div>\n' +
7057    '            </div>\n' +
7058    '        </div>\n' +
7059    '    </li>\n' +
7060    '</ul>\n' +
7061    '<button class="arrow-left arrows ng-hide" ng-click="prev()" ng-show="items.length > 2"></button>\n' +
7062    '<button class="arrow-right arrows right-ar ng-hide" ng-click="next()" ng-show="items.length > 2"></button>\n' +
7063    '');
7064}]);
7065
7066module.exports = "/app/index/templates/post.html";
7067},{}],74:[function(require,module,exports){
7068var ngModule;
7069try {
7070  ngModule = angular.module('templates');
7071} catch (e) {
7072  ngModule = angular.module('templates', []);
7073}
7074
7075ngModule.run(['$templateCache', function ($templateCache) {
7076  $templateCache.put('/app/index/templates/project.html',
7077    '<ul>\n' +
7078    '    <li ng-repeat="item in items track by item.id" class="slide-items">\n' +
7079    '        <a href="{{ item.url }}" class="mosaic__item mosaic__item_two">\n' +
7080    '            <div class="mosaic__img">\n' +
7081    '                <div class="page-top__filter"></div>\n' +
7082    '                <img src="{{ item.background_image.thumb_path }}" alt="{{ item.name }}">\n' +
7083    '            </div>\n' +
7084    '            <div class="mosaic__text">\n' +
7085    '                <h3>{{ item.name }}</h3>\n' +
7086    '            </div>\n' +
7087    '        </a>\n' +
7088    '    </li>\n' +
7089    '</ul>\n' +
7090    '<button class="arrow-left arrows ng-hide" ng-click="prev()" ng-show="items.length > 2"></button>\n' +
7091    '<button class="arrow-right arrows right-ar ng-hide" ng-click="next()" ng-show="items.length > 2"></button>\n' +
7092    '');
7093}]);
7094
7095module.exports = "/app/index/templates/project.html";
7096},{}],75:[function(require,module,exports){
7097var ngModule;
7098try {
7099  ngModule = angular.module('templates');
7100} catch (e) {
7101  ngModule = angular.module('templates', []);
7102}
7103
7104ngModule.run(['$templateCache', function ($templateCache) {
7105  $templateCache.put('/app/index/templates/rubric.html',
7106    '<ul>\n' +
7107    '<li class="slide-projects" ng-repeat="item in items track by item.id">\n' +
7108    '    <div class="mosaic__item mosaic__item_two blog-slide">\n' +
7109    '        <div class="table__item">\n' +
7110    '            <div class="image__block">\n' +
7111    '                <img class="table__img" src="/assets/img/content/{{ item.id }}-b.png">\n' +
7112    '            </div>\n' +
7113    '            <div class="text__block">\n' +
7114    '                <p class="table__title">{{ item.name }}</p>\n' +
7115    '                <p class="table__subtitle" ng-if="item.posts_count">{{ item.posts_count }}</p>\n' +
7116    '                <a href="{{ item.url }}" class="btn-standart btn_slide">{{ item.url_text}}</a>\n' +
7117    '            </div>\n' +
7118    '        </div>\n' +
7119    '    </div>\n' +
7120    '</li>\n' +
7121    '</ul>\n' +
7122    '<button class="arrow-left arrows ng-hide" ng-click="prev()" ng-show="items.length > 2"></button>\n' +
7123    '<button class="arrow-right arrows right-ar ng-hide" ng-click="next()" ng-show="items.length > 2"></button>\n' +
7124    '');
7125}]);
7126
7127module.exports = "/app/index/templates/rubric.html";
7128},{}],76:[function(require,module,exports){
7129'use strict';
7130
7131angular.module('far.insurance')
7132    .controller('InsuranceApplication1Controller', ["$scope", "$log", "$timeout", "$window", "form", "insuranceApplication", function($scope, $log, $timeout, $window, form, insuranceApplication) {
7133        var vm = {
7134            formInsuranceApplication1: form('formInsuranceApplication1'),
7135            form: {},
7136            constructor: function () {
7137                vm.form = insuranceApplication.new({});
7138                vm.form.type = 1;
7139                setTimeout(function () {
7140                    vm.addPerson();
7141                }, 100);
7142            }
7143        };
7144
7145        var formInsuranceApplication1_person = form('formInsuranceApplication1_person');
7146        formInsuranceApplication1_person
7147            .addField('full_name', 'text', {
7148                validators: {
7149                    required: true
7150                },
7151                options: {
7152                    placeholder: 'ФИО'
7153                }
7154            })
7155            .addField('latin_name', 'text', {
7156                validators: {
7157                    required: true
7158                },
7159                options: {
7160                    placeholder: 'Фамилия и имя латиницей (как в загранпаспорте)'
7161                }
7162            })
7163            .addField('birthday', 'dateDropdowns', {
7164                validators: {
7165                    required: true
7166                },
7167                label_before: 'Дата рождения'
7168            })
7169            .addField('member_card', 'text', {
7170                validators: {
7171                    required: false
7172                },
7173                options: {
7174                    placeholder: 'Номер карты члена ФАР',
7175                    style: 'width: 350px;'
7176                }
7177            });
7178
7179        vm.formInsuranceApplication1
7180            .addField('country', 'text', {
7181                validators: {
7182                    required: true
7183                },
7184                options: {
7185                    placeholder: 'Страна поездки',
7186                    class: 'form__item width-300 margin_r_20'
7187                }
7188            })
7189            .addField('sport_kinds', 'selectObject', {
7190                validators: {
7191                    required: true
7192                },
7193                options: {
7194                    defaultOption: 'Вид спорта',
7195                    class: 'form__item form__item_select width-300 margin_r_20'
7196                },
7197                ngOptions: 'item as item.name for item in field.items track by item.id',
7198                label: null
7199            }, [
7200                {id: 2, name: 'альпинизм'},
7201                {id: 3, name: 'Треккинг 1,2,3 степени сложности, I категории сложности'},
7202                {id: 4, name: 'Треккинг II,III,IV,V,VI категории сложности'},
7203                {id: 5, name: 'фрирайд'},
7204                {id: 6, name: 'скалолазание'},
7205                {id: 7, name: 'горные лыжи'},
7206                {id: 8, name: 'сноубординг'},
7207                {id: 9, name: 'парашютный спорт'},
7208                {id: 10, name: 'беговые лыжи'},
7209                {id: 11, name: 'биатлон'},
7210                {id: 12, name: 'велосипедный спорт'},
7211                {id: 13, name: 'дайвинг'},
7212                {id: 14, name: 'водный спорт'},
7213                {id: 15, name: 'мотоцикл'},
7214                {id: 16, name: 'рафтинг'},
7215                {id: 17, name: 'каньонинг'},
7216                {id: 18, name: 'страхование спортивных волонтеров'},
7217                {id: 19, name: 'скитур'},
7218                {id: 20, name: 'скайраннинг'}
7219            ])
7220            .addField('period_from', 'dateDropdowns', {
7221                validators: {
7222                    required: true
7223                },
7224                label_before: 'Период страхования с'
7225            })
7226            .addField('period_till', 'dateDropdowns', {
7227                validators: {
7228                    required: true
7229                },
7230                label_before: 'по'
7231            })
7232            .addField('insurance_sum', 'selectObject', {
7233                validators: {
7234                    required: true
7235                },
7236                options: {
7237                    defaultOption: 'Страховая сумма',
7238                    class: 'form__item form__item_select width-300 margin_r_20'
7239                },
7240                ngOptions: 'item as item.name for item in field.items track by item.id',
7241                label: null
7242            }, [
7243                {id: 1, name: '35 000 $'},
7244                {id: 2, name: '40 000 $'},
7245                {id: 3, name: '50 000 $'},
7246                {id: 4, name: '35 000 €'},
7247                {id: 5, name: '40 000 €'},
7248                {id: 6, name: '50 000 €'}
7249            ])
7250            .addField('baggage', 'checkbox', {
7251                validators: {
7252                    required: false
7253                },
7254                label: 'Включить страхование багажа на перелет туда и обратно (страховая сумма 2000 $/€, cтраховая премия 2 $/€)'
7255            })
7256            .addField('persons_list', 'collection', {
7257                validators: {
7258                    required: true
7259                },
7260                label_before: 'Список лиц, подлежащих страхованию',
7261                buttons: {
7262                    add: 'Добавить лицо',
7263                    remove: 'Удалить'
7264                },
7265                fieldData: {
7266                    doDelete: function(item) {
7267                        item.deleted_at = new Date();
7268                    },
7269                    ngRepeat: 'item in model|filter:field.filterArray track by $index',
7270                    filterArray: function(item) {
7271                        return !item.deleted_at;
7272                    }
7273                }
7274            }, formInsuranceApplication1_person)
7275            .addField('email', 'text', {
7276                validators: {
7277                    required: true,
7278                    emailOnly: ''
7279                },
7280                options: {
7281                    placeholder: 'E-mail заявителя (на указанный e-mail придет информация о стоимости)'
7282                }
7283            }).addField('phone', 'text', {
7284                validators: {
7285                    required: true
7286                    
7287                },
7288                options: {
7289                    placeholder: 'Номер телефона заявителя '
7290                }
7291            });
7292
7293        vm.addPerson = function () {
7294            if (! vm.formInsuranceApplication1.$fields.persons_list.model.length > 0)
7295                vm.formInsuranceApplication1.$fields.persons_list.addItem(vm.formInsuranceApplication1.$fields.persons_list.model);
7296        }
7297
7298        vm.submit = function () {
7299
7300            $log.debug(vm.form);
7301
7302            vm.form.save()
7303                .then(function() {
7304                    $window.location.href = Routing.generate('insurance_index');
7305                })
7306                .catch(function(response) {
7307                    $log.error(response);
7308                    vm.alerts.push({
7309                        type: 'danger',
7310                        message: 'Не удалось сохранить изменения на сервере. Попробуйте повторить попытку через некоторое время.'
7311                    });
7312                });
7313        }
7314
7315        return vm;
7316
7317    }]);
7318
7319},{}],77:[function(require,module,exports){
7320'use strict';
7321
7322angular.module('far.insurance')
7323    .controller('InsuranceApplication2Controller', ["$scope", "$log", "$timeout", "$window", "form", "insuranceApplication", function($scope, $log, $timeout, $window, form, insuranceApplication) {
7324        var vm = {
7325            formInsuranceApplication2: form('formInsuranceApplication2'),
7326            form: {},
7327            constructor: function () {
7328                vm.form = insuranceApplication.new({});
7329                vm.form.type = 2;
7330                setTimeout(function () {
7331                    vm.addPerson2();
7332                }, 100);
7333            }
7334        };
7335
7336        var formInsuranceApplication2_person = form('formInsuranceApplication2_person');
7337        formInsuranceApplication2_person
7338            .addField('full_name', 'text', {
7339                validators: {
7340                    required: true
7341                },
7342                options: {
7343                    placeholder: 'ФИО'
7344                }
7345            })
7346            .addField('birthday', 'dateDropdowns', {
7347                label_before: 'Дата рождения'
7348            })
7349            .addField('member_card', 'text', {
7350                validators: {
7351                    required: false
7352                },
7353                options: {
7354                    placeholder: 'Номер карты члена ФАР',
7355                    style: 'width: 350px;'
7356                }
7357            })
7358            .addField('position', 'text', {
7359                validators: {
7360                    required: true
7361                },
7362                options: {
7363                    placeholder: 'Должность'
7364                }
7365            })
7366            .addField('address', 'text', {
7367                validators: {
7368                    required: true
7369                },
7370                options: {
7371                    placeholder: 'Адрес регистрации (прописки)'
7372                }
7373            })
7374            .addField('passport', 'text', {
7375                validators: {
7376                    required: true
7377                },
7378                options: {
7379                    placeholder: 'Паспортные данные (серия, номер, когда и кем выдан)'
7380                }
7381            })
7382
7383        vm.formInsuranceApplication2
7384            .addField('period_from', 'dateDropdowns', {
7385                validators: {
7386                    required: true
7387                },
7388                label_before: 'Период страхования с'
7389            })
7390            .addField('period_till', 'dateDropdowns', {
7391                validators: {
7392                    required: true
7393                },
7394                label_before: 'по'
7395            })
7396            .addField('insurance_sum', 'selectObject', {
7397                validators: {
7398                    required: true
7399                },
7400                options: {
7401                    defaultOption: 'Страховая сумма, руб.',
7402                    class: 'form__item form__item_select width-300 margin_r_20'
7403                },
7404                ngOptions: 'item as item.name for item in field.items track by item.id',
7405                label: null
7406            }, [
7407                {id: 1, name: '100 000'},
7408                {id: 2, name: '200 000'},
7409                {id: 3, name: '300 000'},
7410                {id: 4, name: '400 000'},
7411                {id: 5, name: '500 000'},
7412                {id: 6, name: '600 000'},
7413                {id: 7, name: '700 000'},
7414                {id: 8, name: '800 000'},
7415                {id: 9, name: '900 000'},
7416                {id: 10, name: '1 000 000'},
7417            ])
7418            .addField('persons_list', 'collection', {
7419                validators: {
7420                    required: true
7421                },
7422                label_before: 'Список лиц, подлежащих страхованию',
7423                buttons: {
7424                    add: 'Добавить лицо',
7425                    remove: 'Удалить'
7426                },
7427                fieldData: {
7428                    doDelete: function(item) {
7429                        item.deleted_at = new Date();
7430                    },
7431                    ngRepeat: 'item in model|filter:field.filterArray track by $index',
7432                    filterArray: function(item) {
7433                        return !item.deleted_at;
7434                    }
7435                }
7436            }, formInsuranceApplication2_person)
7437            .addField('email', 'text', {
7438                validators: {
7439                    required: true,
7440                    emailOnly: ''
7441                },
7442                options: {
7443                    placeholder: 'E-mail заявителя (на указанный e-mail придет информация о стоимости)'
7444                }
7445            });
7446
7447        vm.addPerson2 = function () {
7448            if (! vm.formInsuranceApplication2.$fields.persons_list.model.length > 0)
7449                vm.formInsuranceApplication2.$fields.persons_list.addItem(vm.formInsuranceApplication2.$fields.persons_list.model);
7450        }
7451
7452        vm.submit = function () {
7453
7454            $log.debug(vm.form);
7455
7456            vm.form.save()
7457                .then(function() {
7458                    $window.location.href = Routing.generate('insurance_index');
7459                })
7460                .catch(function(response) {
7461                    $log.error(response);
7462                    vm.alerts.push({
7463                        type: 'danger',
7464                        message: 'Не удалось сохранить изменения на сервере. Попробуйте повторить попытку через некоторое время.'
7465                    });
7466                });
7467        }
7468
7469        return vm;
7470    }]);
7471
7472},{}],78:[function(require,module,exports){
7473'use strict';
7474
7475angular.module('far.insurance')
7476    .controller('InsuranceApplication3Controller', ["$scope", "$log", "$timeout", "$window", "form", "insuranceApplication", function($scope, $log, $timeout, $window, form, insuranceApplication) {
7477        var vm = {
7478            formInsuranceApplication3: form('formInsuranceApplication3'),
7479            form: {},
7480            constructor: function () {
7481                vm.form = insuranceApplication.new({});
7482                vm.form.type = 3;
7483                setTimeout(function () {
7484                    vm.addPerson3();
7485                }, 100);
7486            }
7487        };
7488
7489        var formInsuranceApplication3_person = form('formInsuranceApplication3_person');
7490        formInsuranceApplication3_person
7491            .addField('full_name', 'text', {
7492                validators: {
7493                    required: true
7494                },
7495                options: {
7496                    placeholder: 'ФИО'
7497                }
7498            })
7499            .addField('latin_name',
7499 'text', {
7500                validators: {
7501                    required: true
7502                },
7503                options: {
7504                    placeholder: 'Фамилия и имя латиницей (как в загранпаспорте)'
7505                }
7506            })
7507            .addField('birthday', 'dateDropdowns', {
7508                label_before: 'Дата рождения'
7509            })
7510            .addField('member_card', 'text', {
7511                validators: {
7512                    required: false
7513                },
7514                options: {
7515                    placeholder: 'Номер карты члена ФАР',
7516                    style: 'width: 350px;'
7517                }
7518            })
7519            .addField('address', 'text', {
7520                validators: {
7521                    required: true
7522                },
7523                options: {
7524                    placeholder: 'Адрес регистрации (прописки)'
7525                }
7526            })
7527            .addField('passport', 'text', {
7528                validators: {
7529                    required: true
7530                },
7531                options: {
7532                    placeholder: 'Паспортные данные (серия, номер, когда и кем выдан)'
7533                }
7534            })
7535
7536        vm.formInsuranceApplication3
7537            .addField('country', 'text', {
7538                validators: {
7539                    required: true
7540                },
7541                options: {
7542                    placeholder: 'Страна поездки',
7543                    class: 'form__item width-300 margin_r_20'
7544                }
7545            })
7546            .addField('sport_kinds', 'selectObject', {
7547                validators: {
7548                    required: true
7549                },
7550                options: {
7551                    defaultOption: 'Вид спорта',
7552                    class: 'form__item form__item_select width-300 margin_r_20'
7553                },
7554                ngOptions: 'item as item.name for item in field.items track by item.id',
7555                label: null
7556            }, [
7557                {id: 2, name: 'альпинизм'},
7558                {id: 3, name: 'треккинг'},
7559                {id: 4, name: 'фрирайд'},
7560                {id: 5, name: 'скалолазание'},
7561                {id: 6, name: 'горные лыжи'},
7562                {id: 7, name: 'сноубординг'},
7563                {id: 8, name: 'парашютный спорт'},
7564                {id: 9, name: 'беговые лыжи'},
7565                {id: 10, name: 'биатлон'},
7566                {id: 11, name: 'велосипедный спорт'},
7567                {id: 12, name: 'дайвинг'},
7568                {id: 13, name: 'водный спорт'},
7569                {id: 14, name: 'мотоцикл'},
7570                {id: 15, name: 'рафтинг'},
7571                {id: 16, name: 'каньонинг'},
7572                {id: 17, name: 'страхование спортивных волонтеров'}
7573            ])
7574            .addField('insurance_sum1', 'selectObject', {
7575                validators: {
7576                    required: true
7577                },
7578                options: {
7579                    defaultOption: 'Страховая сумма (Е-экстрим)',
7580                    class: 'form__item form__item_select width-300 margin_r_20'
7581                },
7582                ngOptions: 'item as item.name for item in field.items track by item.id',
7583                label: null
7584            }, [
7585                {id: 1, name: '35 000 $'},
7586                {id: 2, name: '40 000 $'},
7587                {id: 3, name: '50 000 $'},
7588                {id: 4, name: '35 000 €'},
7589                {id: 5, name: '40 000 €'},
7590                {id: 6, name: '50 000 €'}
7591            ])
7592            .addField('insurance_sum2', 'selectObject', {
7593                validators: {
7594                    required: true
7595                },
7596                options: {
7597                    defaultOption: 'Страховая сумма (от НС), руб.',
7598                    class: 'form__item form__item_select width-300 margin_r_20'
7599                },
7600                ngOptions: 'item as item.name for item in field.items track by item.id',
7601                label: null
7602            }, [
7603                {id: 1, name: '100 000'},
7604                {id: 2, name: '200 000'},
7605                {id: 3, name: '300 000'},
7606                {id: 4, name: '400 000'},
7607                {id: 5, name: '500 000'},
7608                {id: 6, name: '600 000'},
7609                {id: 7, name: '700 000'},
7610                {id: 8, name: '800 000'},
7611                {id: 9, name: '900 000'},
7612                {id: 10, name: '1 000 000'},
7613            ])
7614            .addField('period_from', 'dateDropdowns', {
7615                validators: {
7616                    required: true
7617                },
7618                label_before: 'Период страхования с'
7619            })
7620            .addField('period_till', 'dateDropdowns', {
7621                validators: {
7622                    required: true
7623                },
7624                label_before: 'по'
7625            })
7626            .addField('baggage', 'checkbox', {
7627                validators: {
7628                    required: false
7629                },
7630                label: 'Включить страхование багажа на перелет туда и обратно (страховая сумма 2000 $/€, cтраховая премия 2 $/€)'
7631            })
7632            .addField('persons_list', 'collection', {
7633                validators: {
7634                    required: true
7635                },
7636                label_before: 'Список лиц, подлежащих страхованию',
7637                buttons: {
7638                    add: 'Добавить лицо',
7639                    remove: 'Удалить'
7640                },
7641                fieldData: {
7642                    doDelete: function(item) {
7643                        item.deleted_at = new Date();
7644                    },
7645                    ngRepeat: 'item in model|filter:field.filterArray track by $index',
7646                    filterArray: function(item) {
7647                        return !item.deleted_at;
7648                    }
7649                }
7650            }, formInsuranceApplication3_person)
7651            .addField('email', 'text', {
7652                validators: {
7653                    required: true,
7654                    emailOnly: ''
7655                },
7656                options: {
7657                    placeholder: 'E-mail заявителя (на указанный e-mail придет информация о стоимости)'
7658                }
7659            }).addField('phone', 'text', {
7660                validators: {
7661                    required: true
7662                    
7663                },
7664                options: {
7665                    placeholder: 'Номер телефона заявителя '
7666                }
7667            });
7668
7669        vm.addPerson3 = function () {
7670            if (! vm.formInsuranceApplication3.$fields.persons_list.model.length > 0)
7671                vm.formInsuranceApplication3.$fields.persons_list.addItem(vm.formInsuranceApplication3.$fields.persons_list.model);
7672        }
7673
7674        vm.submit = function () {
7675
7676            $log.debug(vm.form);
7677
7678            vm.form.save()
7679                .then(function() {
7680                    $window.location.href = Routing.generate('insurance_index');
7681                })
7682                .catch(function(response) {
7683                    $log.error(response);
7684                    vm.alerts.push({
7685                        type: 'danger',
7686                        message: 'Не удалось сохранить изменения на сервере. Попробуйте повторить попытку через некоторое время.'
7687                    });
7688                });
7689        }
7690
7691        return vm;
7692    }]);
7693
7694},{}],79:[function(require,module,exports){
7695'use strict';
7696
7697angular.module('far.insurance')
7698    .controller('InsuranceWrapperController', ["$scope", "$log", "$timeout", "$window", "$location", "$anchorScroll", function($scope, $log, $timeout, $window, $location, $anchorScroll) {
7699        $anchorScroll.yOffset = 90;
7700
7701        $scope.gotoAnchor = function(x) {
7702            if ($location.hash() !== x) {
7703                $location.hash(x);
7704            } else {
7705                $anchorScroll();
7706            }
7707        };        
7708    }]);
7709
7710},{}],80:[function(require,module,exports){
7711require('./insurance.module');
7712require('./controllers/wrapper.controller');
7713require('./controllers/application1.controller');
7714require('./controllers/application2.controller');
7715require('./controllers/application3.controller');
7716
7717},{"./controllers/application1.controller":76,"./controllers/application2.controller":77,"./controllers/application3.controller":78,"./controllers/wrapper.controller":79,"./insurance.module":81}],81:[function(require,module,exports){
7718'use strict';
7719
7720require('../core/core');
7721require('../../modules/pagination/pagination');
7722require('../../modules/forms/forms');
7723require('../../modules/gallery/gallery');
7724
7725require('../../models/page/page');
7726require('../../models/insurance/insuranceApplication');
7727
7728require('../../modals/slider/slider');
7729
7730require('../../helpers/show-modal-message/show-modal-message');
7731
7732angular.module('far.insurance', [
7733	'ngTouch',
7734	'angularFileUpload',
7735	'ui.select',
7736	'ui.bootstrap',
7737	'dekky.pagination',
7738	'dekky.forms',
7739	'far.models.page',
7740	'far.gallery',
7741	'far.core',
7742	'far.models.insuranceApplication',
7743	'far.modals.slider',
7744	'far.helpers.showModalMessage',
7745	'templates'
7746]).value('formsConfig', {
7747	theme: '/dekky.forms/themes/far'
7748});
7749
7750},{"../../helpers/show-modal-message/show-modal-message":167,"../../modals/slider/slider":182,"../../models/insurance/insuranceApplication":211,"../../models/page/page":221,"../../modules/forms/forms":244,"../../modules/gallery/gallery":332,"../../modules/pagination/pagination":341,"../core/core":38}],82:[function(require,module,exports){
7751'use strict';
7752
7753angular.module('far.mountains')
7754    .controller('MountainRouteAddController', ["$scope", "$log", "$http", "$window", "mountainRouteForm", "mountainRoutes", "$sce", "showModalMessage", function ($scope, $log, $http, $window, mountainRouteForm, mountainRoutes, $sce, showModalMessage) {
7755        var vm = {
7756            progress: true,
7757            mountainRouteModel: mountainRouteForm,
7758            getMountainRoute: getMountainRoute,
7759            submit: submit,
7760            alerts: [],
7761            getDocumentUrl: getDocumentUrl,
7762            closeAlert: function (index) {
7763                vm.alerts.splice(index, 1);
7764            }
7765        };
7766
7767        vm.mountainRouteModel.$fields.description.options.class = 'form__item';
7768        vm.mountainRouteModel.$fields.mountain_peak.uiSelectOptions.onSelect = function(item, model, options) {
7769            if (item) { vm.mountainRoute.mountain_peaks[options.index] = item; }
7770        };
7771        vm.mountainRouteModel.$fields.routeType.options.class = 'form__item form__item_select width-200 margin_r_20';
7772        vm.mountainRouteModel.$fields.routeComplexity.options.class = 'form__item form__item_select width-200 margin_r_20';
7773        vm.mountainRouteModel.$fields.routeUser.options.class = 'form__ui-select width-340';
7774        vm.mountainRouteModel.$fields.routeUser.uiSelectOptions.onSelect = function (item) {
7775            if (item) { vm.mountainRoute.user = item; }
7776        };
7777         vm.mountainRouteModel.$fields.newRouteUserFirstName.options.class = 'form__item  width-200 margin_r_20';
7778                 vm.mountainRouteModel.$fields.newRouteUserLastName.options.class = 'form__item  width-200 margin_r_20';
7779
7780        vm.mountainRouteModel.$fields.slidesFiles.uploader.onSuccessItem = function (item, response) {
7781            vm.mountainRoute.slides_files.push(response);
7782        };
7783        vm.mountainRouteModel.$fields.documentsFiles.uploader.removeFromQueue = function (value) {
7784            var index = this.getIndexOfItem(value);
7785            var item = this.queue[index];
7786
7787            if (item.isUploading) {
7788                item.cancel();
7789            } else {
7790                vm.documents_files.splice(index, 1);
7791            }
7792
7793            this.queue.splice(index, 1);
7794            item._destroy();
7795
7796            this.progress = this._getTotalProgress();
7797        };
7798
7799        function getDocumentUrl(file_id) {
7800            return Routing.generate('api_upload_get_file', {fileStorage: file_id});
7801        }
7802
7803        function getMountainRoute() {
7804            if (arguments.length == 0) {
7805                vm.mountainRoute = mountainRoutes.new({
7806                    mountain_peaks: [],
7807                    slides_files: [],
7808                    documents_files: []
7809                });
7810                vm.mountainRoute.mountain_peaks = [undefined];
7811                vm.progress = false;
7812            } else {
7813                vm.mountainRoute = mountainRoutes.get(arguments[0], function () {
7814                    if (vm.mountainRoute.mountain_peaks.length == 0) {
7815                        vm.mountainRoute.mountain_peaks.push();
7816                    }
7817                    vm.progress = false;
7818                });
7819            }
7820        }
7821
7822        function submit() {
7823            console.log(vm.mountainRoute);
7824
7825            vm.mountainRoute.documents_files = vm.mountainRoute.documents_files.concat(
7826                vm.documents_files
7827                    .filter(function (document) {
7828                        return document.isUploaded;
7829                    })
7830                    .map(function (document) {
7831                        return document.serverData;
7832                    })
7833            );
7834            vm.mountainRouteModel.$fields.documentsFiles.uploader.clearQueue();
7835
7836            vm.mountainRoute.slides_files = vm.mountainRoute.slides_files.map(function(slide, index) {
7837                slide.sort = index + 1;
7838                return slide;
7839            });
7840            if(!vm.mountainRoute.user)
7841                vm.mountainRoute.user=0;
7842
7843            vm.mountainRoute.save()
7844                .then(function () {
7845                    var message = $sce.trustAsHtml('Маршрут успешно сохранен');
7846                    var modalInstance = showModalMessage(message);
7847                    modalInstance.result
7848                        .then(function() {
7849                            $window.location.href = Routing.generate('mountains_routes_by_peak');
7850                        }, function() {
7851                            $window.location.href = Routing.generate('mountains_routes_by_peak');
7852                        });
7853                })
7854                .catch(function (response) {
7855                    $log.error(response);
7856                    var message = 'Возникла проблема при сохранении маршрута. Попробуйте позже.';
7857                    var modalInstance = showModalMessage(message);
7858                    modalInstance.result
7859                        .then(function() {
7860                            $window.location.href = Routing.generate('mountains_routes_by_peak');
7861                        }, function() {
7862                            $window.location.href = Routing.generate('mountains_routes_by_peak');
7863                        });
7864                });
7865        }
7866
7867        return vm;
7868    }]);
7869
7870},{}],83:[function(require,module,exports){
7871'use strict';
7872
7873angular.module('far.mountains')
7874.controller('RouteDescriptionController', ["$log", "FileUploader", "mountainRoutes", "fileUploadFilters", "showModalMessage", "$uibModal", "$window", "$http", function($log, FileUploader, mountainRoutes, fileUploadFilters, showModalMessage, $uibModal, $window, $http) {
7875	var showFilterError = false;
7876
7877	var vm = {
7878        params: {
7879            mountainRoute: null,
7880            limit: 5,
7881            offset: 0
7882        },
7883		showPaging: true,
7884        total: {
7885            count: 0,
7886            pages: null
7887        },
7888        data: [],
7889
7890		initUploadUrl: initUploadUrl,
7891		openSlider: openSlider,
7892		openRouteImagesUploader: openRouteImagesUploader,
7893		uploader: new FileUploader({
7894			url: '',
7895			autoUpload: true,
7896			filters: [
7897				fileUploadFilters.fileSize(),
7898				fileUploadFilters.fileType()
7899			],
7900			onSuccessItem: function (item, response) {
7901				item.serverData = response;
7902			},
7903			onWhenAddingFileFailed: function(item, filter) {
7904				if (showFilterError) return;
7905
7906				var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
7907
7908				showFilterError = true;
7909				var modalInstance = showModalMessage(message);
7910				modalInstance.result
7911					.then(function() {
7912						showFilterError = false;
7913					}, function() {
7914						showFilterError = false;
7915					});
7916			},
7917			onErrorItem: function() {
7918				if (showFilterError) return;
7919
7920				showFilterError = true;
7921				var modalInstance = showModalMessage('Невозможно загрузить файл на сервер');
7922				modalInstance.result
7923					.then(function() {
7924						showFilterError = false;
7925					}, function() {
7926						showFilterError = false;
7927					});
7928			}
7929		}),
7930		getFileLink: function(file) {
7931			if (file.isUploading) {
7932				return '';
7933			}
7934
7935			if (file.isSuccess) {
7936				return Routing.generate('api_upload_get_file', {'fileStorage': file.serverData.id});
7937			}
7938
7939			return '';
7940		},
7941        submit: function ( next ) {
7942            if (vm.submitted) {
7943                return false;
7944            }
7945
7946            vm.params.mountainRoute = vm.mountainRoute.id;
7947
7948            if ( !next ) {
7949                vm.params.offset = 0;
7950
7951
7952                vm.total.count = 0;
7953                vm.total.pages = null;
7954
7955                vm.data = [];
7956            }
7957
7958            vm.submitted = true;
7959
7960            $http.get(Routing.generate('api_entities_get_mountain_route_ascents', vm.params)).then(function (response) {
7961                vm.total.count = response.headers('X-Total-Count');
7962                vm.total.pages = Math.ceil( vm.total.count / vm.params.limit );
7963
7964                if ( response.data ) {
7965                	if (response.data.html) {
7966						$('.mountain-route-ascents').append($(response.data.html));
7967					} else {
7968						vm.showPaging = false;
7969					}
7970                }
7971
7972                vm.submitted = false;
7973                vm.loaded = false;
7974            }, function errorCallback(response) {
7975                $log.error(response);
7976
7977                vm.submitted = false;
7978            });
7979        },
7980        next: function () {
7981            vm.params.offset += vm.params.limit;
7982
7983            vm.submit( true );
7984        }
7985	};
7986
7987	function initUploadUrl(id) {
7988		vm.uploader.url = Routing.generate('api_upload_post_mountainroute_file', {'id': id});
7989		vm.mountainRoute = mountainRoutes.get(id);
7990	}
7991
7992	function openSlider(slide) {
7993		$uibModal.open({
7994			templateUrl: '/modals/slider/slider.html',
7995			controller: 'SliderController as slider',
7996			resolve: {
7997				slides: function() {
7998					return vm.mountainRoute.slides_files;
7999				},
8000				selectedSlide: function() {
8001					return slide;
8002				}
8003			}
8004		});
8005	}
8006
8007	function openRouteImagesUploader(isAdmin) {
8008		var modalRouteImagesInstance = $uibModal.open({
8009			templateUrl: '/modals/mountain-route-images/mountain-route-images.html',
8010			controller: 'MountainRouteImagesController as routeImages',
8011			windowClass: 'modal-route',
8012			backdrop: 'static',
8013			keyboard: false,
8014			resolve: {
8015				mountainRoute: function() {
8016					return vm.mountainRoute;
8017				},
8018				isAdmin: function() {
8019					return isAdmin
8020				}
8021			}
8022		});
8023
8024		modalRouteImagesInstance.result.then(
8025			function() {
8026				//$window.location.reload(true);
8027			},
8028			function(result) {
8029				if (result && result.error) {
8030					showModalMessage(result.error);
8031				}
8032			}
8033		);
8034	}
8035
8036	return vm;
8037}]);
8038
8039},{}],84:[function(require,module,exports){
8040'use strict';
8041
8042angular.module('far.mountains')
8043.controller('MountainsRoutesByPeakController', ["$log", "$http", "$document", "pagination", "$q", "mountainRoutes", function($log, $http, $document, pagination, $q, mountainRoutes) {
8044	var oldMountainPeak = null;
8045	var vm = {
8046		hasSubmitted: false,
8047		pagination: pagination('mountainsRoutes', {next: nextPage, itemsOnPage: 9000}),
8048		mountainPeak: null,
8049		searchMountainRoutes: searchMountainRoutes,
8050		refreshAutocomplete: refreshAutocomplete,
8051		mountainPeaks: [],
8052		popularRoutes: [],
8053		totalPages: 0,
8054		getUserProfileUrl: getUserProfileUrl,
8055		getPeaksStringForRoute: getPeaksStringForRoute,
8056		getAreaStringForRoute: getAreaStringForRoute,
8057		getRegionStringForRoute: getRegionStringForRoute,
8058		getHeightStringForRoute: getHeightStringForRoute,
8059		getMountainRouteUrl: getMountainRouteUrl,
8060		addMyAscentUrl: addMyAscentUrl,
8061		trRouteClass: trRouteClass
8062	};
8063
8064	function refreshAutocomplete(peakName) {
8065		vm.mountainPeaks.length = 0;
8066
8067		if (!peakName) {
8068			return vm.mountainPeaks;
8069		}
8070
8071		return $http.post(Routing.generate('api_entities_post_autocomplete'), {
8072			term: 'Mountain',
8073			search: peakName
8074		}).then(function(response) {
8075			vm.mountainPeaks.length =  0;
8076			response.data.forEach(function(peak) {
8077				vm.mountainPeaks.push(peak);
8078			});
8079		});
8080	}
8081
8082	function searchMountainRoutes() {
8083		$document.scrollTopAnimated(350);
8084
8085		vm.hasSubmitted = true;
8086		if (
8087			vm.mountainPeak &&
8088			(!oldMountainPeak || oldMountainPeak.id != vm.mountainPeak.id)
8089		) {
8090			vm.pagination.clear();
8091			if (!oldMountainPeak || oldMountainPeak.mountain_area_id != vm.mountainPeak.mountain_area_id) {
8092				getPopularRoutes({area_id: vm.mountainPeak.mountain_area_id});
8093			}
8094			oldMountainPeak = vm.mountainPeak;
8095		}
8096	}
8097
8098	function nextPage(page, count) {
8099		return $http.get(Routing.generate('api_entities_get_mountainroutes', {
8100			offset: (page - 1) * count,
8101			limit: count,
8102			mountain_id: vm.mountainPeak.id
8103		})).then(function(response) {
8104			var items = [];
8105			vm.totalPages = Math.ceil(response.headers('X-Total-Count') / count);
8106
8107			angular.forEach(response.data, function(item) {
8108				console.log(item[0]);
8109				items.push(item[0]);
8110			});
8111
8112			return items;
8113		}).catch(function(response) {
8114			$log.error(response);
8115			return $q.reject(response);
8116		});
8117	}
8118
8119	function getRegionStringForRoute(route) {
8120		var _return = [];
8121		route.mountain_peaks.map(function(peak) {
8122			_return.push(peak.mountain_region_name);
8123		});
8124		return _return[0];
8125	}
8126
8127	function getAreaStringForRoute(route) {
8128		var _return = [];
8129		route.mountain_peaks.map(function(peak) {
8130			_return.push(peak.mountain_area_name);
8131		});
8132		return _return[0];
8133	}
8134
8135	function getPeaksStringForRoute(route) {
8136		return route.mountain_peaks.map(function(peak) {
8137			var _return = [];
8138			
8139			if ( peak.name ) {
8140				_return.push(peak.name);
8141			}
8142
8143			return _return.join(', ');
8144		}).join(' - ');
8145	}
8146
8147	function getHeightStringForRoute(route) {
8148		var _return = [];
8149		route.mountain_peaks.map(function(peak) {
8150			_return.push(peak.height);
8151		});
8152		if(_return.length > 1) {
8153			return '';
8154		}
8155		return _return[0];
8156	}
8157
8158	function getUserProfileUrl(route) {
8159		return Routing.generate('user_view', {userId: route.user.id});
8160	}
8161
8162	function addMyAscentUrl(route) {
8163		return Routing.generate('personal_alpbook') + '#/?mountainroute=' + route.id;
8164	}
8165
8166	function getMountainRouteUrl(route) {
8167		return Routing.generate('page_mountainroute_index', {'id': route.id});
8168	}
8169
8170	function trRouteClass(status) {
8171		if(status) {
8172			return 'page-table__row'
8173		}
8174		return 'page-table__row_colored'
8175	}
8176
8177	function getPopularRoutes(filters) {
8178		vm.popularRoutes = [];
8179		mountainRoutes.getPopular(filters)
8180				.then(function(routes) {
8181					angular.forEach(routes, function(route) {
8182						vm.popularRoutes.push(route[0]);
8183					});
8184				});
8185	}
8186	getPopularRoutes();
8187
8188	return vm;
8189}]);
8190
8191},{}],85:[function(require,module,exports){
8192'use strict';
8193
8194angular.module('far.mountains')
8195	.controller('MountainsRoutesByRegionController', ["$scope", "$log", "$http", "$timeout", "$document", "$q", "pagination", "form", "mountainRoutes", "mountainReg
8195ions", "mountainRouteTypes", "mountainRouteComplexities", function(
8196		$scope,
8197		$log,
8198		$http,
8199		$timeout,
8200		$document,
8201		$q,
8202		pagination,
8203		form,
8204		mountainRoutes,
8205		mountainRegions,
8206		mountainRouteTypes,
8207		mountainRouteComplexities
8208	) {
8209		var vm = {
8210			hasSubmitted: false,
8211			pagination: pagination('mountainsRoutes', {next: nextPage,itemsOnPage: 100}),
8212			totalPages: 0,
8213			peaksFilter: form('peaksFilter'),
8214			popularRoutes: [],
8215            startOffset: 0,
8216			peaksFilterModel: {
8217				mountain_area: null,
8218				mountain_region: null,
8219				mountain: null
8220			},
8221			moreFilterModel: {
8222				route_types: mountainRouteTypes.list,
8223				route_complexities: mountainRouteComplexities.list,
8224				peak_height: {
8225					min: 0,
8226					max: 8848,
8227					options: {
8228						floor: 0,
8229						ceil: 8848,
8230						step: 100
8231					}
8232				},
8233				sortBy: false
8234			},
8235			peaksFilterSubmit: peaksFilterSubmit,
8236			moreFilterSubmit: moreFilterSubmit,
8237			showFilters: false,
8238			canShowFilters: false,
8239			getPeaksStringForRoute: getPeaksStringForRoute,
8240			getHeightStringForRoute: getHeightStringForRoute,
8241			getMountainRouteUrl: getMountainRouteUrl,
8242			getUserProfileUrl: getUserProfileUrl,
8243			clearFilters: clearFilters,
8244			getAreaStringForRoute: getAreaStringForRoute,
8245			getRegionStringForRoute: getRegionStringForRoute,
8246			addMyAscentUrl: addMyAscentUrl,
8247			trRouteClass: trRouteClass
8248		};
8249
8250		vm.peaksFilter
8251			.addField('mountainRegion', 'selectObject', {
8252				validators: {
8253					required: true
8254				},
8255				options: {
8256					ngChange: changeRegion,
8257					class: 'form__item form__item_select'
8258				},
8259				ngOptions: 'item as item.name for item in field.items track by item.id',
8260				label: null
8261			}, mountainRegions.list)
8262			.addField('mountainArea', 'selectObject', {
8263				options: {
8264					ngChange: changeArea,
8265					class: 'form__item form__item_select'
8266				},
8267				ngOptions: 'item as item.name for item in field.items track by item.id',
8268				label: null
8269			}, [])
8270			.addField('mountain', 'selectObject', {
8271				ngOptions: 'item as (item.name) for item in field.items track by item.id',
8272				label: null,
8273				options: {
8274                    ngChange: function () {
8275                        $timeout(function() {
8276                            vm.moreFilterSubmit();
8277                        });
8278                    },
8279					class: 'form__item form__item_select'
8280				}
8281			}, []);
8282
8283		function changeRegion() {
8284            mountainRegions.setAddBlank(true);
8285
8286			$timeout(function() {
8287				//vm.mountain.mountainArea = null;
8288				if (vm.peaksFilterModel.mountain_region) {
8289					vm.peaksFilter.$fields.mountain.items = [];
8290
8291					mountainRegions.list.forEach(function(region) {
8292						if (region.id == vm.peaksFilterModel.mountain_region.id) {
8293							vm.peaksFilter.$fields.mountainArea.items = region.mountain_areas;
8294
8295							$log.debug(vm.peaksFilter.$fields.mountainArea.items);
8296						}
8297					});
8298
8299					vm.peaksFilterSubmit();
8300
8301                    $document.scrollToElementAnimated(document.getElementById('peaks_filter_form'), 20);
8302				}
8303			});
8304		}
8305
8306		function changeArea() {
8307			$timeout(function() {
8308				//vm.mountain.mountainArea = null;
8309				if (vm.peaksFilterModel.mountain_area) {
8310					if ( vm.peaksFilterModel.mountain_area.id == 0 ) {
8311						vm.peaksFilter.$fields.mountain.items = [];
8312
8313						return;
8314					}
8315
8316					$http.get(Routing.generate('api_entities_get_mountains_by_area', {mountainArea: vm.peaksFilterModel.mountain_area.id}))
8317						.then(function(response) {
8318							vm.peaksFilter.$fields.mountain.items = [];
8319							console.log('mountains_by_area',response.data);
8320
8321							if ( response.data.length ) {
8322								vm.peaksFilter.$fields.mountain.items.push({
8323									id: 0,
8324									name: '...'
8325								});
8326
8327								response.data.forEach(function(mountain) {
8328									vm.peaksFilter.$fields.mountain.items.push(mountain)
8329								});
8330
8331                                vm.moreFilterSubmit();
8332							}
8333						})
8334						.catch(function(response) {
8335							$log.error(response);
8336							vm.peaksFilter.$fields.mountain.items = [];
8337						});
8338
8339                    //$document.scrollToElementAnimated(document.getElementById('peaks_filter_form'), 20);
8340				}
8341			});
8342		}
8343
8344		function getFilters() {
8345			return {
8346				area_id: vm.peaksFilterModel.mountain_area ? vm.peaksFilterModel.mountain_area.id : null,
8347				region_id: vm.peaksFilterModel.mountain_region ? vm.peaksFilterModel.mountain_region.id : null,
8348				mountain_id: vm.peaksFilterModel.mountain ? vm.peaksFilterModel.mountain.id : null,
8349				route_complexities: vm.moreFilterModel.route_complexities.filter(function(route_complexity) {
8350					return angular.isDefined(route_complexity.selected) && route_complexity.selected == true;
8351				}).map(function(route_complexity) {
8352					return route_complexity.id;
8353				}),
8354				route_types: vm.moreFilterModel.route_types.filter(function(route_type) {
8355					return angular.isDefined(route_type.selected) && route_type.selected == true;
8356				}).map(function(route_type) {
8357					return route_type.id;
8358				}),
8359				peak_height_min: vm.moreFilterModel.peak_height.min,
8360				peak_height_max: vm.moreFilterModel.peak_height.max,
8361                order_by: vm.moreFilterModel.sortBy ? 'ascents_count,desc' : ''
8362			}
8363		}
8364		function clearFilters() {
8365			vm.moreFilterModel.peak_height.min = 0;
8366			vm.moreFilterModel.peak_height.max = 8848;
8367			vm.moreFilterModel.route_complexities.forEach(function(route_complexity) {
8368				if (angular.isDefined(route_complexity.selected)) {
8369					delete route_complexity.selected;
8370				}
8371			});
8372			vm.moreFilterModel.route_types.forEach(function(route_type) {
8373				if (angular.isDefined(route_type.selected)) {
8374					delete route_type.selected;
8375				}
8376			});
8377		}
8378
8379		function nextPage(page, count) {
8380			return $http.get(Routing.generate('api_entities_get_mountainroutes',
8381				angular.merge({}, getFilters(), {
8382					offset: vm.startOffset + (page - 1) * count,
8383					limit: count
8384				})
8385			)).then(function(response) {
8386				var items = [];
8387				vm.totalPages = Math.ceil(response.headers('X-Total-Count') / count);
8388				console.log('get_mountainroutes',response.data);
8389				angular.forEach(response.data, function(item) {
8390					items.push(item[0]);
8391				});
8392
8393				return items;
8394			}).catch(function(response) {
8395				$log.error(response);
8396				return $q.reject(response);
8397			})
8398		}
8399
8400		function peaksFilterSubmit() {
8401			vm.hasSubmitted = true;
8402			clearFilters();
8403			vm.canShowFilters = true;
8404
8405			vm.pagination.clear();
8406
8407			// Обновляем список популярных маршрутов
8408			var popularFilters = {
8409				area_id: vm.peaksFilterModel.mountain_area ? vm.peaksFilterModel.mountain_area.id : null,
8410				region_id: vm.peaksFilterModel.mountain_region ? vm.peaksFilterModel.mountain_region.id : null
8411			};
8412			getPopularRoutes(popularFilters);
8413		}
8414
8415		function moreFilterSubmit() {
8416			vm.showFilters = false;
8417			vm.pagination.clear();
8418		}
8419
8420		function getPeaksStringForRoute(route) {
8421			return route.mountain_peaks.map(function(peak) {
8422				var _return = [];
8423
8424				if ( peak.name ) {
8425					_return.push(peak.name);
8426				}
8427
8428				return _return.join(', ');
8429			}).join(' - ');
8430		}
8431
8432		function getRegionStringForRoute(route) {
8433			var _return = [];
8434			route.mountain_peaks.map(function(peak) {
8435				_return.push(peak.mountain_region_name);
8436			});
8437			return _return[0];
8438		}
8439
8440		function getAreaStringForRoute(route) {
8441			var _return = [];
8442			route.mountain_peaks.map(function(peak) {
8443				_return.push(peak.mountain_area_name);
8444			});
8445			return _return[0];
8446		}
8447
8448		function getHeightStringForRoute(route) {
8449			var _return = [];
8450			route.mountain_peaks.map(function(peak) {
8451				_return.push(peak.height);
8452			});
8453			if(_return.length > 1) {
8454				return '';
8455			}
8456			return _return[0];
8457		}
8458
8459		function getUserProfileUrl(route) {
8460			if (route.user) {
8461				return Routing.generate('user_view', {userId: route.user.id});
8462			}
8463		}
8464
8465		function getMountainRouteUrl(route) {
8466			return Routing.generate('page_mountainroute_index', {'id': route.id});
8467		}
8468
8469		function addMyAscentUrl(route) {
8470			return Routing.generate('personal_alpbook') + '#/?mountainroute=' + route.id;
8471		}
8472
8473		function trRouteClass(status) {
8474			if(status) {
8475				return 'page-table__row'
8476			}
8477			return 'page-table__row_colored'
8478		}
8479
8480		function getPopularRoutes(filters) {
8481			vm.popularRoutes = [];
8482			mountainRoutes.getPopular(filters)
8483				.then(function(routes) {
8484					angular.forEach(routes, function(route) {
8485						vm.popularRoutes.push(route[0]);
8486					});
8487				});
8488		}
8489		getPopularRoutes();
8490
8491		return vm;
8492	}]);
8493
8494},{}],86:[function(require,module,exports){
8495require('./mountains.module');
8496require('./controllers/newRoute.controller');
8497require('./controllers/routesByPeak.controller');
8498require('./controllers/routesByRegion.controller');
8499require('./controllers/routeDescription.controller');
8500
8501},{"./controllers/newRoute.controller":82,"./controllers/routeDescription.controller":83,"./controllers/routesByPeak.controller":84,"./controllers/routesByRegion.controller":85,"./mountains.module":87}],87:[function(require,module,exports){
8502'use strict';
8503
8504require('../core/core');
8505require('../../modules/pagination/pagination');
8506require('../../modules/forms/forms');
8507require('../../modules/gallery/gallery');
8508
8509require('../../models/mountains/regions');
8510require('../../models/mountains/mountains');
8511require('../../models/mountains/routes');
8512require('../../models/mountains/routeTypes');
8513require('../../models/mountains/routeComplexities');
8514
8515require('../../modals/slider/slider');
8516require('../../modals/mountain-route-images/mountain-route-images');
8517
8518require('../../forms/mountainRouteForm');
8519
8520require('../../helpers/show-modal-message/show-modal-message');
8521
8522angular.module('far.mountains', [
8523	'ngTouch',
8524	'angularFileUpload',
8525	'ui.select',
8526	'ui.bootstrap',
8527	'dekky.pagination',
8528	'dekky.forms',
8529	'far.models.mountains.routes',
8530	'far.models.mountains.regions',
8531	'far.models.mountains.mountains',
8532	'far.models.mountains.routeTypes',
8533	'far.models.mountains.routeComplexities',
8534	'far.gallery',
8535	'far.core',
8536	'far.modals.slider',
8537	'far.helpers.showModalMessage',
8538	'far.forms.mountainRouteForm',
8539	'far.modals.mountain-route-images',
8540	'templates',
8541	'duScroll'
8542]).value('formsConfig', {
8543	theme: '/dekky.forms/themes/far'
8544});
8545
8546},{"../../forms/mountainRouteForm":152,"../../helpers/show-modal-message/show-modal-message":167,"../../modals/mountain-route-images/mountain-route-images":178,"../../modals/slider/slider":182,"../../models/mountains/mountains":212,"../../models/mountains/regions":214,"../../models/mountains/routeComplexities":215,"../../models/mountains/routeTypes":216,"../../models/mountains/routes":217,"../../modules/forms/forms":244,"../../modules/gallery/gallery":332,"../../modules/pagination/pagination":341,"../core/core":38}],88:[function(require,module,exports){
8547'use strict';
8548
8549angular.module('far.news')
8550    .controller('NewsArchiveController', ["$log", "$http", function($log, $http) {
8551        var vm = {
8552            loaded: true,
8553            submitted: false,
8554            params: {
8555                limit: 10,
8556                offset: 0
8557            },
8558            total: {
8559                count: 0,
8560                pages: null
8561            },
8562            data: [],
8563            submit: function ( next ) {
8564                if (vm.submitted) {
8565                    return false;
8566                }
8567
8568                if ( !next ) {
8569                    vm.params.offset = 0;
8570
8571                    vm.total.count = 0;
8572                    vm.total.pages = null;
8573
8574                    vm.data = [];
8575                }
8576
8577                vm.submitted = true;
8578
8579                $http.get(Routing.generate('api_get_newsarchive', vm.params)).then(function (response) {
8580                    vm.total.count = response.headers('X-Total-Count');
8581                    vm.total.pages = Math.ceil( vm.total.count / vm.params.limit );
8582
8583                    if ( response.data ) {
8584                        response.data.forEach(function(news) {
8585                            news['url'] = Routing.generate('news_archive_view', {id: news.id});
8586
8587                            vm.data.push(news);
8588                        });
8589                    }
8590
8591                    vm.submitted = false;
8592                    vm.loaded = false;
8593                }, function errorCallback(response) {
8594                    $log.error(response);
8595
8596                    vm.submitted = false;
8597                });
8598            },
8599            next: function () {
8600                vm.params.offset += vm.params.limit;
8601
8602                vm.submit( true );
8603            }
8604        };
8605
8606        vm.submit();
8607
8608        return vm;
8609    }]);
8610
8611},{}],89:[function(require,module,exports){
8612'use strict';
8613
8614angular.module('far.news')
8615	.controller('NewsEditController', ["$log", "$http", "$rootScope", "News", "Discipline", "Committee", "NewsCategory", "newsForm", "showModalMessage", "softdeleteable", function ($log, $http, $rootScope, News, Discipline, Committee, NewsCategory, newsForm, showModalMessage, softdeleteable) {
8616		var vm = {
8617			progress: true,
8618			submitted: false,
8619            event: undefined,
8620			form: {},
8621			fields: newsForm,
8622			constructor: function (news, event) {
8623                if ( event ) {
8624                    $http.get(Routing.generate('api_event_get_event', {id: event}))
8625                        .then(function(response) {
8626                            vm.event = response.data;
8627                            vm.news( news );
8628                        })
8629                        .catch(function(response) {
8630                            $log.error(response);
8631                        });
8632                } else {
8633                    vm.news( news );
8634                }
8635			},
8636            news: function( news ) {
8637                if ( news ) {
8638                    vm.form = News.get(news, function() {
8639                        vm.disciplines();
8640                        vm.categories();
8641                        vm.committees();
8642                        
8643                        softdeleteable.setModel(News);
8644
8645                        vm.progress = false;
8646                    });
8647                } else {
8648                    vm.form = News.new({
8649                        slides_files: []
8650                    });
8651
8652                    if ( vm.event ) {
8653                        vm.form.disciplines = vm.event.disciplines;
8654
8655                        vm.disciplines();
8656                        vm.categories();
8657                        vm.committees();
8658                    }
8659
8660                    vm.progress = false;
8661                }
8662
8663                vm.fields.$fields.slides_files.uploader.onSuccessItem = function (item, response) {
8664                    vm.form.slides_files.push(response);
8665                };
8666            },
8667			submit: function () {
8668                vm.form.slides_files = vm.form.slides_files.map(function(slide, index) {
8669                    slide.sort = index + 1;
8670                    return slide;
8671                });
8672
8673                if ( vm.event ) {
8674                    vm.form.event = vm.event.id;
8675                }
8676
8677                if (vm.form.youtube) {
8678                    var regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
8679                    var match = vm.form.youtube.match(regExp);
8680
8681                    if (match && match[2].length === 11) {
8682                        vm.form.youtube = 'https://www.youtube.com/embed/' + match[2];
8683                    }
8684                }
8685
8686				vm.form.save()
8687					.then(function (response) {
8688						document.location.href=Routing.generate('news_view', {id: response.data.id});
8689					})
8690					.catch(function (response) {
8691						$log.error(response);
8692						showModalMessage('Не удалось сохранить изменения на сервере. Попробуйте повторить попытку через некоторое время.');
8693					});
8694			},
8695            disciplines: function () {
8696                var disciplineWatch = $rootScope.$watch(function() {
8697                    return Discipline.list.length;
8698                }, function(newVal) {
8699                    if (newVal > 0) {
8700                        Discipline.list.forEach(function(discipline_item) {
8701                            /* if ( vm.event ) {
8702                                discipline_item.disabled = true;
8703                            } */
8704
8705                            if ( angular.isArray( vm.form.disciplines ) ) {
8706                                vm.form.disciplines.forEach(function(selectedDiscipline) {
8707                                    if (discipline_item.id == selectedDiscipline.id) {
8708                                        discipline_item.selected = true;
8709                                    }
8710                                });
8711                            }
8712                        });
8713                        disciplineWatch();
8714                    }
8715                });
8716            },
8717            committees: function () {
8718                var committeeWatch = $rootScope.$watch(function() {
8719                    return Committee.list.length;
8720                }, function(newVal) {
8721                    if (newVal > 0) {
8722                        Committee.list.forEach(function(committee_item) {
8723                            /* if ( vm.event ) {
8724                                committee_item.disabled = true;
8725                            } */
8726
8727                            if ( angular.isArray( vm.form.committees ) ) {
8728                                vm.form.committees.forEach(function(selectedCommittee) {
8729                                    if (committee_item.id == selectedCommittee.id) {
8730                                        committee_item.selected = true;
8731                                    }
8732                                });
8733                            }
8734                        });
8735                        committeeWatch();
8736                    }
8737                });
8738            },
8739            categories: function () {
8740                var categoryWatch = $rootScope.$watch(function() {
8741                    return NewsCategory.list.length;
8742                }, function(newVal) {
8743                    if (newVal > 0) {
8744                        NewsCategory.list.forEach(function(category_item) {
8745                            /* if ( vm.event ) {
8746                                category_item.disabled = true;
8747                            } */
8748
8749                            if ( angular.isArray( vm.form.categories ) ) {
8750                                vm.form.categories.forEach(function(selectedNewsCategory) {
8751                                    if (category_item.id == selectedNewsCategory.id) {
8752                                        category_item.selected = true;
8753                                    }
8754                                });
8755                            }
8756                        });
8757
8758                        categoryWatch();
8759                    }
8760                });
8761            },
8762            delete: function() {
8763                vm.deleted = true;
8764
8765                softdeleteable.delete(vm.form.id);
8766            },
8767            restore: function() {
8768                vm.deleted = false;
8769
8770                softdeleteable.restore(vm.form.id);
8771            }
8772		};
8773
8774		vm.fields.$fields.avatar.uploader.onSuccessItem = function (item, response) {
8775			vm.form.avatar = response;
8776		};
8777
8778		return vm;
8779	}]);
8780
8781},{}],90:[function(require,module,exports){
8782'use strict';
8783
8784angular.module('far.news')
8785    .controller('NewsIndexController', ["$log", "$http", function($log, $http) {
8786        var vm = {
8787            loaded: true,
8788            submitted: false,
8789            params: {
8790                limit: 10,
8791                offset: 0,
8792                category: null,
8793                discipline: null
8794            },
8795            total: {
8796                count: 0,
8797                pages: null
8798            },
8799            data: [],
8800            setDiscipline: function ( discipline ) {
8801                vm.params.discipline = discipline;
8802
8803                vm.submit();
8804            },
8805            submit: function ( next ) {
8806                if (vm.submitted) {
8807                    return false;
8808                }
8809
8810                if ( !next ) {
8811                    vm.params.offset = 0;
8812
8813                    vm.total.count = 0;
8814                    vm.total.pages = null;
8815
8816                    vm.data = [];
8817                }
8818
8819                vm.submitted = true;
8820
8821                $http.get(Routing.generate('api_get_newslist', vm.params)).then(function (response) {
8822                    vm.total.count = response.headers('X-Total-Count');
8823                    vm.total.pages = Math.ceil( vm.total.count / vm.params.limit );
8824
8825                    if ( response.data ) {
8826                        response.data.forEach(function(news) {
8827                            news['url'] = Routing.generate('news_view', {id: news.id});
8828
8829                            news.disciplines = news.disciplines.map(function (discipline) {
8830                                discipline['url'] = Routing.generate('discipline_index', {url: discipline.url});
8831
8832                                return discipline;
8833                            });
8834
8835                            vm.data.push(news);
8836                        });
8837                    }
8838
8839                    vm.submitted = false;
8840                    vm.loaded = false;
8841                }, function errorCallback(response) {
8842                    $log.error(response);
8843
8844                    vm.submitted = false;
8845                });
8846            },
8847            next: function () {
8848                vm.params.offset += vm.params.limit;
8849
8850                vm.submit( true );
8851            }
8852        };
8853
8854        return vm;
8855    }]);
8856
8857},{}],91:[function(require,module,exports){
8858'use strict';
8859
8860angular.module('far.news')
8861    .controller('NewsViewController', ["$log", "FileUploader", "News", "fileUploadFilters", "showModalMessage", "$uibModal", function($log, FileUploader, News, fileUploadFilters, showModalMessage, $uibModal) {
8862        var showFilterError = false;
8863
8864        var vm = {
8865            progress: true,
8866            initNews: initNews,
8867            openSlider: openSlider
8868        };
8869
8870        function initNews(id) {
8871            vm.news = News.getView(id, function () {
8872                vm.progress = false;
8873            });
8874        }
8875
8876        function openSlider(slide) {
8877            $uibModal.open({
8878                templateUrl: '/modals/slider/slider.html',
8879                controller: 'SliderController as slider',
8880                resolve: {
8881                    slides: function() {
8882                        return vm.news.slides_files;
8883                    },
8884                    selectedSlide: function() {
8885                        return slide;
8886                    }
8887                }
8888            });
8889        }
8890
8891        return vm;
8892    }]);
8893
8894},{}],92:[function(require,module,exports){
8895require('./news.module');
8896require('./controllers/edit.controller');
8897require('./controllers/view.controller');
8898require('./controllers/index.controller');
8899require('./controllers/archive.controller');
8900
8901},{"./controllers/archive.controller":88,"./controllers/edit.controller":89,"./controllers/index.controller":90,"./controllers/view.controller":91,"./news.module":93}],93:[function(require,module,exports){
8902'use strict';
8903
8904require('../core/core');
8905require('../../modules/pagination/pagination');
8906require('../../modules/forms/forms');
8907require('../../modules/gallery/gallery');
8908
8909require('../../models/news/news');
8910require('../../models/news/newsCategory');
8911require('../../models/discipline/discipline');
8912require('../../models/committee/committee');
8913
8914require('../../forms/newsForm');
8915
8916require('../../modals/slider/slider');
8917
8918require('../../helpers/show-modal-message/show-modal-message');
8919
8920require('ng-masonry');
8921
8922angular.module('far.news', [
8923	'ngTouch',
8924	'angularFileUpload',
8925	'ui.select',
8926	'ui.bootstrap',
8927	'dekky.pagination',
8928	'dekky.forms',
8929	'far.models.news',
8930	'far.models.newsCategory',
8931	'far.models.discipline',
8932    'far.models.committee',
8933	'far.forms.newsForm',
8934	'far.gallery',
8935	'far.core',
8936	'far.modals.slider',
8937	'far.helpers.showModalMessage',
8938    'ngMasonry'
8939]).value('formsConfig', {
8940	theme: '/dekky.forms/themes/far'
8941});
8942
8943},{"../../forms/newsForm":153,"../../helpers/show-modal-message/show-modal-message":167,"../../modals/slider/slider":182,"../../models/committee/committee":191,"../../models/discipline/discipline":196,"../../models/news/news":218,"../../models/news/newsCategory":219,"../../modules/forms/forms":244,"../../modules/gallery/gallery":332,"../../modules/pagination/pagination":341,"../core/core":38,"ng-masonry":9}],94:[function(require,module,exports){
8944'use strict';
8945
8946angular.module('far.page')
8947    .controller('PageViewController', ["$log", "FileUploader", "Page", "fileUploadFilters", "showModalMessage", "$uibModal", function($log, FileUploader, Page, fileUploadFilters, showModalMessage, $uibModal) {
8948        var showFilterError = false;
8949
8950        var vm = {
8951            initUploadUrl: initUploadUrl,
8952            openSlider: openSlider,
8953            uploader: new FileUploader({
8954                url: '',
8955                autoUpload: true,
8956                filters: [
8957                    fileUploadFilters.fileSize(),
8958                    fileUploadFilters.fileType()
8959                ],
8960                onSuccessItem: function (item, response) {
8961                    item.serverData = response;
8962                },
8963                onWhenAddingFileFailed: function(item, filter) {
8964                    if (showFilterError) return;
8965
8966                    var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
8967
8968                    showFilterError = true;
8969                    var modalInstance = showModalMessage(message);
8970                    modalInstance.result
8971                        .then(function() {
8972                            showFilterError = false;
8973                        }, function() {
8974                            showFilterError = false;
8975                        });
8976                }
8977            }),
8978            getFileLink: function(file) {
8979                if (file.isUploading) {
8980                    return '';
8981                }
8982
8983                if (file.isSuccess) {
8984                    return Routing.generate('api_upload_get_file', {'fileStorage': file.serverData.id});
8985                }
8986
8987                return '';
8988            }
8989        };
8990
8991        function initUploadUrl(id) {
8992            vm.uploader.url = Routing.generate('api_upload_post_mountainroute_file', {'id': id});
8993            vm.page = Page.get(id);
8994        }
8995
8996        function openSlider(slide) {
8997            $uibModal.open({
8998                templateUrl: '/modals/slider/slider.html',
8999                controller: 'SliderController as slider',
9000                resolve: {
9001                    slides: function() {
9002                        return vm.page.slides_files;
9003                    },
9004                    selectedSlide: function() {
9005                        return slide;
9006                    }
9007                }
9008            });
9009        }
9010
9011        return vm;
9012    }]);
9013
9014},{}],95:[function(require,module,exports){
9015require('./page.module');
9016require('./controllers/view.controller');
9017
9018},{"./controllers/view.controller":94,"./page.module":96}],96:[function(require,module,exports){
9019'use strict';
9020
9021require('../core/core');
9022require('../../modules/pagination/pagination');
9023require('../../modules/forms/forms');
9024require('../../modules/gallery/gallery');
9025
9026require('../../models/page/page');
9027
9028require('../../modals/slider/slider');
9029
9030require('../../helpers/show-modal-message/show-modal-message');
9031
9032angular.module('far.page', [
9033	'ngTouch',
9034	'angularFileUpload',
9035	'ui.select',
9036	'ui.bootstrap',
9037	'dekky.pagination',
9038	'dekky.forms',
9039	'far.models.page',
9040	'far.gallery',
9041	'far.core',
9042	'far.modals.slider',
9043	'far.helpers.showModalMessage',
9044	'templates'
9045]).value('formsConfig', {
9046	theme: '/dekky.forms/themes/far'
9047});
9048
9049},{"../../helpers/show-modal-message/show-modal-message":167,"../../modals/slider/slider":182,"../../models/page/page":221,"../../modules/forms/forms":244,"../../modules/gallery/gallery":332,"../../modules/pagination/pagination":341,"../core/core":38}],97:[function(require,module,exports){
9050'use strict';
9051
9052angular.module('far.profile')
9053.controller('AscentProfileController', ["$log", "$http", "$window", "$timeout", "$scope", "$location", "Ascents", "mountainReg
9053ions", "mountainPeaks", "mountainRoutes", "ascentEditForm", "showModalMessage", "UserRelation", function (
9054	$log,
9055	$http,
9056	$window,
9057	$timeout,
9058	$scope,
9059	$location,
9060	Ascents,
9061	mountainRegions,
9062	mountainPeaks,
9063	mountainRoutes,
9064	ascentEditForm,
9065	showModalMessage,
9066	UserRelation
9067) {
9068	var vm = {
9069		getDocumentUrl: getDocumentUrl,
9070		progress: false,
9071		ascentModel: ascentEditForm(),
9072		getAscent: getAscent,
9073		submit: submit,
9074		newAscent: newAscent,
9075		selectedPeak: null,
9076		userId: null,
9077		isEditAscent: false,
9078		showAscentsForm: false,
9079		mountain: null,
9080		alerts: [],
9081		ascents: [],
9082        masterSelected: null,
9083		showAdditionalField: showAdditionalField,
9084		editAscent: editAscent,
9085		deleteAscent: deleteAscent,
9086		closeAlert: function(index) {
9087			vm.alerts.splice(index, 1);
9088		}
9089	};
9090
9091	function showAdditionalField(field) {
9092        if (field.name === 'master_selector') {
9093			return vm.ascent.ascent_user_type
9094				&& vm.ascent.ascent_user_type.id === vm.ascent_user_types.participant.id;
9095        }
9096
9097        if(field.name === 'user_chief'){
9098            return vm.ascent.ascent_user_type
9099				&& vm.ascent.ascent_user_type.id === vm.ascent_user_types.participant.id
9100				&& vm.masterSelected !== null
9101				&& vm.masterSelected.model === vm.ascent_user_types.chief.system_name;
9102		}
9103
9104        if(field.name === 'user_instructor'){
9105            return vm.ascent.ascent_user_type
9106				&& vm.ascent.ascent_user_type.id === vm.ascent_user_types.participant.id
9107                && vm.masterSelected !== null
9108				&& vm.masterSelected.model === vm.ascent_user_types.instructor.system_name;
9109        }
9110    }
9111
9112	function ascentFormAdditionals() {
9113		vm.ascentModel.$fields.ascent_type.options.class = 'form__item form__item_select';
9114		vm.ascentModel.$fields.ascent_user_type.options.class = 'form__item form__item_select';
9115		vm.ascentModel.$fields.ascent_mountain_route.options.class = 'form__item form__item_select';
9116        vm.ascentModel.$fields.master_selector.radio.model = vm.masterSelected;
9117		vm.ascentModel.$fields.master_selector.radioAttributes.onSelect = function(item){
9118			vm.masterSelected = item;
9119		};
9120		vm.ascentModel.$fields.ascent_mountain_peak.uiSelectOptions.onSelect = function(item) {
9121			if (item && item.id != vm.selectedPeak) {
9122				vm.selectedPeak = item;
9123				refreshMountainRouteAutoComplete();
9124			}
9125		};
9126		vm.ascentModel.$fields.user_chief.uiSelectOptions.onSelect = function(item, model, options) {
9127			vm.ascent.updateUser(options.index, item);
9128		};
9129        vm.ascentModel.$fields.user_instructor.uiSelectOptions.onSelect = function(item, model, options) {
9130            vm.ascent.updateUser(options.index, item);
9131        };
9132		vm.ascentModel.$fields.user_participant.uiSelectOptions.onSelect = function (item, model, options) {
9133			vm.ascent.updateUser(options.index, item);
9134		};
9135		vm.ascentModel.$fields.documentsFiles.uploader.removeFromQueue = function(value) {
9136			var index = this.getIndexOfItem(value);
9137			var item = this.queue[index];
9138
9139			if (item.isUploading) {
9140				item.cancel();
9141			} else {
9142				vm.documents_files.splice(index, 1);
9143			}
9144
9145			this.queue.splice(index, 1);
9146			item._destroy();
9147
9148			this.progress = this._getTotalProgress();
9149		};
9150	}
9151	ascentFormAdditionals();
9152
9153	function getDocumentUrl(file_id) {
9154		return Routing.generate('api_upload_get_file', {fileStorage: file_id});
9155	}
9156
9157	function getAscent() {
9158		vm.ascent = Ascents.new({}, vm.ascent_user_types);
9159		vm.progress = false;
9160	}
9161
9162	function refreshMountainRouteAutoComplete() {
9163		$http.get(Routing.generate('api_entities_get_mountainroutes', {
9164			offset: 0,
9165			limit: 100,
9166			peak_id: vm.selectedPeak.id,
9167			list: 1
9168		})).then(function(response) {
9169			vm.ascentModel.$fields.ascent_mountain_route.items.length = 0;
9170
9171			angular.forEach(response.data, function (route) {
9172				vm.ascentModel.$fields.ascent_mountain_route.items.push(route[0]);
9173			});
9174		}).catch(function(response) {
9175			$log.error(response);
9176		});
9177	}
9178
9179	function deleteAscent(ascentId) {
9180		var ascent = { id: ascentId };
9181
9182		Ascents
9183			.delete(ascent)
9184			.then(function() {
9185				$window.location.reload(true);
9186			})
9187			.catch( function(response) {
9188				$log.error(response);
9189				vm.alerts.push({
9190					type: 'danger',
9191					message: 'Не удалось удалить восхождение. Попробуйте повторить попытку через некоторое время.'
9192				});
9193				vm.progress = false;
9194			});
9195	}
9196
9197	function editAscent(ascentId) {
9198		vm.ascentModel.$fields.documentsFiles.uploader.clearQueue();
9199		vm.masterSelected = null;
9200
9201		vm.ascent = Ascents.get(arguments[0], vm.ascent_user_types, function (ascentData) {
9202            vm.ascent.ascent_users.filter(function(user){
9203            	if(user.user && user.user.id === vm.userId){
9204            		vm.ascent.ascent_user_type = user.ascent_user_type_id;
9205				}
9206				if(user.user && (user.ascent_user_type_id.id === vm.ascent_user_types.chief.id || user.ascent_user_type_id.id === vm.ascent_user_types.instructor.id)){
9207                    var radioItem = vm.ascentModel.$fields.master_selector.items.filter(function(item){
9208                    	return item.model === user.ascent_user_type_id.system_name
9209					});
9210                    vm.masterSelected = radioItem.length ? radioItem[0] : null;
9211				}
9212			});
9213			vm.ascent.ascent_date = new Date(vm.ascent.ascent_date);
9214			vm.selectedPeak = ascentData.ascent_mountain_route.mountain_peaks[0];
9215			refreshMountainRouteAutoComplete();
9216
9217			vm.isEditAscent = true;
9218			vm.progress = false;
9219		});
9220	}
9221
9222	function newAscent(route) {
9223		vm.progress = true;
9224		if (vm.isEditAscent) {
9225			vm.isEditAscent = false;
9226			vm.showAscentsForm = false;
9227		}
9228
9229		vm.ascent = Ascents.new({}, vm.ascent_user_types);
9230
9231		if (route) {
9232			vm.ascent.ascent_mountain_route = route;
9233			vm.selectedPeak = route.mountain_peaks[0];
9234			refreshMountainRouteAutoComplete();
9235		} else {
9236			vm.selectedPeak = null;
9237		}
9238
9239
9240		vm.ascentModel = undefined;
9241		$timeout(function() {
9242			vm.ascentModel = ascentEditForm();
9243			ascentFormAdditionals();
9244			vm.showAscentsForm = !vm.showAscentsForm;
9245			vm.progress = false;
9246		});
9247	}
9248
9249	function submit() {
9250		if (vm.progress || !$scope.ascentForm.$valid) {
9251			return;
9252		}
9253
9254        var ascent_users_error = true;
9255
9256        vm.ascent.ascent_users.filter(function(user) {
9257            if (user.user) {
9258                ascent_users_error = false;
9259            }
9260        });
9261
9262        if (ascent_users_error) {
9263            //vm.ascent.ascent_users_error = true;
9264
9265            //return;
9266		} else {
9267            //vm.ascent.ascent_users_error = null;
9268        }
9269
9270		vm.progress = true;
9271		vm.showAscentsForm = false;
9272		vm.isEditAscent = false;
9273
9274        var addUser = true;
9275
9276        vm.ascent.ascent_users.map(function(user) {
9277            if (user.user && (user.user.id == vm.userId)) {
9278                addUser = false;
9279                user.ascent_user_type_id = vm.ascent.ascent_user_type;
9280            }
9281
9282            if(vm.masterSelected && vm.masterSelected.model === 'chief' && user.user && user.ascent_user_type_id.id == vm.ascent_user_types.instructor.id){
9283            	vm.ascent.deleteUser(user);
9284			}
9285            if(vm.masterSelected && vm.masterSelected.model === 'instructor' && user.user && user.ascent_user_type_id.id == vm.ascent_user_types.chief.id){
9286                vm.ascent.deleteUser(user);
9287            }
9288        });
9289
9290        if (addUser) {
9291            var _user = vm.ascent.createUser(vm.ascent.ascent_user_type);
9292
9293            vm.ascent.updateUser(_user.uniqId, {id: vm.userId});
9294        }
9295
9296		vm.ascent.save()
9297			.then(function() {
9298				$window.location.reload(true);
9299			})
9300			.catch(function(response) {
9301				$log.error(response);
9302				showModalMessage('Не удалось сохранить изменения на сервере. Попробуйте повторить попытку через некоторое время.');
9303				vm.progress = false;
9304			});
9305	}
9306
9307	if (angular.isDefined($location.search().mountainroute)) {
9308		mountainRoutes.get($location.search().mountainroute, function(route) {
9309			newAscent(route);
9310		});
9311	}
9312
9313	return vm;
9314}]);
9315
9316},{}],98:[function(require,module,exports){
9317'use strict';
9318
9319angular.module('far.profile')
9320    .controller('ProfileDischargeController', ["$rootScope", "Notice", "softdeleteable", "pagination", "form", "autocomplete", "$scope", "$http", function (
9321        $rootScope,
9322        Notice,
9323        softdeleteable,
9324        pagination,
9325        form,
9326        autocomplete,
9327        $scope,
9328        $http
9329    ) {
9330        var vm = {
9331            form: {},
9332            submit: submit,
9333            fields: form('ProfileDischarge'),
9334            progress: false,
9335            submitted: false,
9336            user: null,
9337            userQualificationNotificationId: null,
9338
9339            setId: setId,
9340            constructor: function (user) {
9341                vm.user = user;
9342            }
9343        };
9344
9345        vm.fields
9346            .addField('user', 'uiSelect', {
9347                options: {
9348                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
9349                    class: 'form__ui-select',
9350                    ngRequired: 'field.uiSelectOptions.required()',
9351                    ngDisabled: 'field.uiSelectOptions.disabled()'
9352                },
9353                uiSelectOptions: {
9354                    matchTitle: '{{ $select.selected.fio }} ',
9355                    choicesTitle: '{{ item.fio }}',
9356                    match: {
9357                        placeholder: 'Альпинисты',
9358                        allowClear: true
9359                    },
9360                    choices: {
9361                        repeat: 'item in field.items track by item.id',
9362                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "user")',
9363                        refreshDelay: 0
9364                    },
9365                    refreshAutoComplete: autocomplete.refreshAutoComplete,
9366                    onSelect: function (item) {
9367                        vm.form.user = item;
9368                    },
9369                    required: function() {
9370                        return true;
9371                    },
9372                    disabled: function() {
9373                        return false;
9374                    }
9375                }
9376            }, autocomplete.get('user'))
9377            ;
9378
9379        function submit() {
9380            vm.submitted = true;
9381            vm.show_error = true;
9382
9383            $http.put(Routing.generate('api_put_user_qualification_notification', {userQualificationNotificationId: vm.userQualificationNotificationId, userId: vm.form.user.id}))
9384                .then(function (response) {
9385                    alert('Спасибо!');
9386                    document.location.reload();
9387                }, function errorCallback(response) {
9388                    $log.error(response);
9389
9390                    vm.submitted = true;
9391                });
9392
9393            vm.submitted = false;
9394        }
9395
9396        function setId(id) {
9397            vm.userQualificationNotificationId = id;
9398        }
9399
9400        return vm;
9401    }]);
9402
9403},{}],99:[function(require,module,exports){
9404/**
9405 * Created by phatbass on 2/9/16.
9406 */
9407
9408angular.module('far.profile')
9409    .controller('ProfileEditController', ["$q", "$http", "$scope", "$log", "$window", "form", "User", "userQualification", "userClub", "userAward", "hideShowPassword", "autocomplete", "softdeleteable", "showModalMessage", "http", function ($q, $http, $scope, $log, $window, form, User, userQualification, userClub, userAward, hideShowPassword, autocomplete, softdeleteable, showModalMessage, http) {
9410
9411        var instructorCategories = [];
9412        var conductorCategories = [];
9413        var vm = {
9414            progress: true,
9415            submitted: false,
9416            deleted: false,
9417            formName: '',
9418            form: {},
9419            clubEditDisabled: false,
9420            valid: {},
9421            blur: {},
9422            errors: [],
9423            modal_choose: false,
9424            achievements: {},
9425            achievements_errors: {},
9426            achievements_as_type: {},
9427            achievements_value: {
9428                judge_qualification: [],
9429                coach_qualification: [],
9430                champion_russia: [],
9431                world_champion: [],
9432                european_champion: [],
9433                russian_cup: [],
9434                european_cup: [],
9435                world_cup: []
9436            },
9437            club_other_items: [
9438            {
9439                id: 0,
9440                name: 'Отдать голос представителю региональной федерации'
9441             },
9442            // {
9443            //     id: 1,
9444            //     name: 'Отдать голос президенту ФАР, во время голосования Ваш голос будет учтен в ФАиС Москвы'
9445            // },
9446            {
9447                id: 2,
9448                name: 'Принимает участие в конференции лично'
9449            }],
9450            constructor: function (user, isAdmin) {
9451                vm.isAdmin = isAdmin;
9452                vm.form = User.get(user, function () {
9453
9454                    vm.currentInstructorCategory = vm.form.instructor_category ? vm.form.instructor_category : null;
9455
9456                    instructorCategories.push(
9457                        {
9458                            id: 1,
9459                            name: 1
9460                        },
9461                        {
9462                            id: 2,
9463                            name: 2
9464                        },
9465                        {
9466                            id: 3,
9467                            name: 3
9468                        }
9469                    );
9470
9471                    if (vm.isAdmin || vm.currentInstructorCategory == 4) {
9472                        instructorCategories.push({
9473                            id: 4,
9474                            name: 'ИНП, ИГП'
9475                        });
9476                    }
9477
9478                    vm.currentConductorCategory = vm.form.conductor_category ? vm.form.conductor_category : null;
9479
9480                    conductorCategories.push(
9481                        {
9482                            id: 1,
9483                            name: 'до 2А к.сл.'
9484                        },
9485                        {
9486                            id: 2,
9487                            name: 'до 3Б к.сл.'
9488                        },
9489                        {
9490                            id: 3,
9491                            name: 'до 4Б к.сл.'
9492                        },
9493                        {
9494                            id: 4,
9495                            name: 'до 5Б к.сл.'
9496                        }
9497                    );
9498                     
9499                    vm.clubEditDisabled = vm.form.club && Date.parse(vm.form.member_date_end) > Date.now();
9500                        vm.form.club_next = vm.form.club ? vm.form.club.id : null;
9501                    if (angular.isObject(vm.form.country)) {
9502                        vm.autoCompleteSelect.country = vm.form.country.id;
9503                    }
9504              
9505
9506                    vm.form.enabled = {
9507                        id: vm.form.enabled
9508                    };
9509
9510                    vm.form.gender = {
9511                        id: vm.form.gender
9512                    };
9513
9514                    vm.form.instructor_category = {
9515                        id: vm.form.instructor_category
9516                    };
9517
9518                    vm.form.conductor_category = {
9519                        id: vm.form.conductor_category
9520                    };
9521
9522                    vm.form.awards = {};
9523
9524                    if (angular.isArray(vm.form.user_awards)) {
9525                        for (var key in vm.form.user_awards) {
9526                            var award = vm.form.user_awards[key];
9527                            var system_name = award.type.system_name;
9528
9529                            if (vm.form.awards[system_name] == undefined) {
9530                                vm.form.awards[system_name] = [];
9531                            }
9532
9533                            award.type = award.type.id;
9534
9535                            vm.form.awards[system_name].push(award);
9536                        }
9537                    }
9538
9539                    for ( var key in vm.form.achievements ) {
9540                        var achievement =  vm.form.achievements[ key ];
9541
9542                        if ( vm.achievements[ achievement.type.system_name ] == undefined ) {
9543                            vm.achievements[ achievement.type.system_name ] = [];
9544                        }
9545
9546                        if ( angular.isArray( achievement.type.value ) && achievement.type.value.length > 0 ) {
9547                            achievement.value = {
9548                                id: achievement.value
9549                            }
9550                        }
9551
9552                        vm.achievements[ achievement.type.system_name ].push({
9553                            value: achievement.value,
9554                            year: achievement.year
9555                        })
9556                    }
9557
9558                    $q.all({
9559                        achievement_types: $http.get(Routing.generate('api_get_user_achievement_types')),
9560                        award_type: $http.get(Routing.generate('api_get_user_award_type'))
9561                    }).then(function (values) {
9562                        for ( var key in values.achievement_types.data ) {
9563                            vm.achievements_as_type[ key ] = values.achievement_types.data[ key ].id;
9564
9565                            if ( vm.achievements[ key ] == undefined ) {
9566                                vm.achievements[ key ] = [{}];
9567                            }
9568
9569                            var value = values.achievement_types.data[ key ].value;
9570
9571                            if ( angular.isArray( value ) && value.length > 0 ) {
9572                                for ( var i in value ) {
9573                                    vm.achievements_value[ key ].push( value[ i ] );
9574                                }
9575                            }
9576                        }
9577
9578                        var userAwardTypes = values.award_type.data;
9579
9580                        for (var userAwardType in userAwardTypes) {
9581                            if (vm.form.awards[userAwardTypes[userAwardType].system_name] == undefined) {
9582                                vm.form.awards[userAwardTypes[userAwardType].system_name] = [{
9583                                    type: userAwardTypes[userAwardType].id
9584                                }];
9585                            }
9586                        }
9587
9588                        softdeleteable.setModel(User);
9589
9590                        vm.progress = false;
9591                    });
9592                })
9593            },
9594            autoCompleteSelect: {
9595                country: null,
9596                region: null,
9597                city: null
9598            },
9599            formUserEdit: form('formUserEdit'),
9600            hideShowPassword: hideShowPassword,
9601            submit: function () {
9602                if ( vm.submitted ) {
9603                    return false;
9604                }
9605                 if(!vm.form.club){
9606                   return false;
9607                }
9608                vm.submitted = true;
9609
9610                if ( angular.isObject( vm.achievements ) ) {
9611                    vm.form.achievements = [];
9612                    vm.achievements_errors = {};
9613
9614                    var achievements_data = angular.merge({}, vm.achievements);
9615
9616                    dance:
9617                    for ( var system_name in achievements_data ) {
9618                        var achievements = achievements_data[ system_name ];
9619
9620                        if ( angular.isArray( achievements ) ) {
9621                            for ( var key in achievements ) {
9622                                var achievement = achievements[ key ];
9623
9624                                if ( angular.isObject( achievement.value ) ) {
9625                                    achievement.value = achievement.value.id;
9626                                }
9627
9628                                if( system_name == 'climbing_everest' && achievement.year ) {
9629                                    achievement.value = true;
9630                                }
9631
9632                                if ( achievement.value && achievement.year ) {
9633                                    vm.form.achievements.push({
9634                                        user: vm.form.id,
9635                                        year: achievement.year,
9636                                        value: achievement.value,
9637                                        type: vm.achievements_as_type[ system_name ]
9638                                    });
9639                                } else if ( achievement.value || achievement.year ) {
9640                                    if( system_name != 'climbing_everest' ) {
9641                                        vm.achievements_errors[system_name] = true;
9642
9643                                        vm.submitted = false;
9644
9645                                        return false;
9646                                    }
9647                                }
9648                            }
9649                        }
9650                    }
9651                }
9652
9653                if ( angular.isObject( vm.form.club ) && !vm.form.club_position ) {
9654                    vm.form.club_position = userClub.position[0];
9655                }
9656
9657                if ( angular.isObject( vm.form.alpclub ) && !vm.form.alpclub_position ) {
9658                    vm.form.alpclub_position = userClub.position[0];
9659                }
9660
9661                const newDate = new Date(vm.form['instructor_period_start']);
9662                 // Apply the increment
9663                newDate.setFullYear(newDate.getFullYear() + 5);
9664                vm.form['instructor_period_end'] = newDate;
9665
9666                vm.form.save()
9667                    .then(function () {
9668                        $window.location.reload(true);
9669                    }, function errorCallback(response) {
9670                        response = http.authenticationListener(response);
9671
9672                        vm.errors = [];
9673
9674                        if (angular.isDefined(response.data.errors) ) {
9675                            for ( var key in response.data.errors ) {
9676                                vm.errors.push(response.data.errors[key]);
9677                            }
9678                        } else {
9679                            showModalMessage('Ошибка на сервере. Попробуйте позже.');
9680                        }
9681
9682                        vm.submitted = false;
9683                    });
9684            },
9685            delete: function() {
9686                vm.deleted = true;
9687
9688                softdeleteable.delete(vm.form.id);
9689            },
9690            restore: function() {
9691                vm.deleted = false;
9692
9693                softdeleteable.restore(vm.form.id);
9694            }
9695        };
9696
9697        vm.formUserEdit
9698            .addField('enabled', 'selectObject', {
9699                validators: {
9700                    required: false
9701                },
9702                options: {
9703                    defaultOption: 'Статус пользователя',
9704                    class: 'form__item form__item_select margin_b_40'
9705                },
9706                ngOptions: 'item as item.name for item in field.items track by item.id',
9707            }, [
9708                {
9709                    id: true,
9710                    name: 'Активный'
9711                },
9712                {
9713                    id: false,
9714                    name: 'Заблокированный'
9715                }
9716            ])
9717            .addField('member_card', 'text', {
9718                validators: {
9719                    required: false,
9720                    numericOnly: ''
9721                },
9722                options: {
9723                    placeholder: 'Номер карты',
9724                    class: 'form__item width-130'
9725                }
9726            })
9727            .addField('member_date_end', 'dateDropdowns', {
9728                label: null,
9729                options: {
9730                    ngDisabled: function () {
9731                        if (vm.form.member_card) {
9732                            return false
9733                        } else {
9734                            return true;
9735                        }
9736                    }
9737                }
9738            })
9739            .addField('died', 'checkbox', {
9740                validators: {
9741                    required: false
9742                },
9743                label: 'Поместить в раздел "Памяти"'
9744            })
9745            .addField('phone', 'text', {
9746                validators: {
9747                    required: false
9748                },
9749                options: {
9750                    placeholder: 'Телефон'
9751                }
9752            })
9753            .addField('email', 'text', {
9754                validators: {
9755                    required: true
9756                },
9757                options: {
9758                    placeholder: 'E-mail'
9759                }
9760            })
9761            .addField('last_name', 'text', {
9762                validators: {
9763                    required: true
9764                },
9765                options: {
9766                    placeholder: 'Фамилия'
9767                }
9768            })
9769            .addField('first_name', 'text', {
9770                validators: {
9771                    required: true
9772                },
9773                options: {
9774                    placeholder: 'Имя'
9775                }
9776            })
9777            .addField('middle_name', 'text', {
9778                validators: {
9779                    required: false
9780                },
9781                options: {
9782                    placeholder: 'Отчество'
9783                }
9784            })
9785            .addField('gender', 'selectObject', {
9786                validators: {
9787                    required: false
9788                },
9789                options: {
9790                    defaultOption: 'Пол',
9791                    class: 'form__item form__item_select margin_b_40'
9792                },
9793                ngOptions: 'item as item.name for item in field.items track by item.id'
9794            }, [
9795                {
9796                    id: 'male',
9797                    name: 'Мужчина'
9798                },
9799                {
9800                    id: 'female',
9801                    name: 'Женщина'
9802                }
9803            ])
9804            .addField('birthday', 'dateDropdowns', {
9805                label: null
9806            })
9807            .addField('social_vk', 'text', {
9808                validators: {
9809                    required: false,
9810                    urlOnly: ''
9811                },
9812                options: {
9813                    class: 'form__item width-290',
9814                    placeholder: 'Вконтакте'
9815                }
9816            })
9817            .addField('social_fb', 'text', {
9818                validators: {
9819                    required: false,
9820                    urlOnly: ''
9821                },
9822                options: {
9823                    class: 'form__item width-290',
9824                    placeholder: 'Facebook'
9825                }
9826            })
9827            .addField('social_in', 'text', {
9828                validators: {
9829                    required: false,
9830                    urlOnly: ''
9831                },
9832                options: {
9833                    class: 'form__item width-290',
9834                    placeholder: 'Instagram'
9835                }
9836            })
9837            .addField('post_index', 'text', {
9838                validators: {
9839                    required: false,
9840                    numericOnly: ''
9841                },
9842                options: {
9843                    placeholder: 'Индекс'
9844                }
9845            })
9846            .addField('address', 'text', {
9847                validators: {
9848                    required: false
9849                },
9850                options: {
9851                    placeholder: 'Улица'
9852                }
9853            })
9854            .addField('house', 'text', {
9855                validators: {
9856                    required: false
9857                },
9858                options: {
9859                    placeholder: 'Дом'
9860                }
9861            })
9862            .addField('building', 'text', {
9863                validators: {
9864                    required: false
9865                },
9866                options: {
9867                    placeholder: 'Кор.'
9868                }
9869            })
9870            .addField('apartment', 'text', {
9871                validators: {
9872                    required: false
9873                },
9874                options: {
9875                    placeholder: 'Кв.'
9876                }
9877            })
9878            .addField('club_position', 'selectObject', {
9879                validators: {
9880                    required: false
9881                },
9882                options: {
9883                    defaultOption: 'Статус пользователя',
9884                    class: 'form__item form__item_select width-200',
9885                    ngDisabled: function () {
9886                        if (vm.form.club) {
9887                            return false;
9888                        } else {
9889                            return true;
9890                        }
9891                    }
9892                },
9893                ngOptions: 'item as item.name for item in field.items track by item.id',
9894                label: null
9895            }, userClub.positionList)
9896            .addField('club_editor', 'checkbox', {
9897                validators: {
9898                    required: false
9899                },
9900                options: {
9901                    ngDisabled: function () {
9902                        if (vm.form.club) {
9903                            return false;
9904                        } else {
9905                            return true;
9906                        }
9907                    }
9908                },
9909                label: 'Редактор федерации'
9910            })
9911            /*
9912            .addField('club_additional', 'text', {
9913                validators: {
9914                    required: false
9915                },
9916                options: {
9917                    placeholder: 'Клуб'
9918                }
9919            })
9920            */
9921            .addField('alpclub', 'uiSelect', {
9922                validators: {
9923                    required: false
9924                },
9925                options: {
9926                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
9927                    class: 'form__ui-select width-400 margin_r_40'
9928                },
9929                uiSelectOptions: {
9930                    matchTitle: '{{ $select.selected.name }} ',
9931                    choicesTitle: '{{ item.name }}',
9932                    match: {
9933                        placeholder: 'Альпинистский клуб',
9934                        allowClear: true
9935                    },
9936                    choices: {
9937                        repeat: 'item in field.items track by item.id',
9938                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Club", "club")',
9939                        refreshDelay: 400
9940                    },
9941                    refreshAutoComplete: function(name, term, object) {
9942                        var parent = vm.form.club ? vm.form.club.id : null;
9943
9944                        var params = {};
9945                        params.subclub = 'true';
9946                      // if (parent) {
9947                     //       params.parent_club = parent;
9948                     //   }
9949                        return autocomplete.refreshAutoComplete(name, term, object, params)
9950                    },
9951                    onSelect: function (item) {
9952                        vm.form.alpclub = item;
9953                    }
9954                }
9955            }, autocomplete.get('club'))
9956            .addField('alpclub_position', 'selectObject', {
9957                validators: {
9958                    required: false
9959                },
9960                options: {
9961                    defaultOption: 'Статус пользователя',
9962                    class: 'form__item form__item_select width-200',
9963                    ngDisabled: function () {
9964                        if (vm.form.alpclub) {
9965                            return false;
9966                        } else {
9967                            return true;
9968                        }
9969                    }
9970                },
9971                ngOptions: 'item as item.name for item in field.items track by item.id',
9972                label: null
9973            }, userClub.positionList) //clubPosition
9974            .addField('alpclub_editor', 'checkbox', {
9975                validators: {
9976                    required: false
9977                },
9978                options: {
9979                    ngDisabled: function () {
9980                        if (vm.form.alpclub) {
9981                            return false;
9982                        } else {
9983                            return true;
9984                        }
9985                    }
9986                },
9987                label: 'Редактор клуба'
9988            })
9989            .addField('qualification', 'selectObject', {
9990                validators: {
9991                    required: false
9992                },
9993                options: {
9994                    defaultOption: 'Квалификация',
9995                    class: 'form__item form__item_select width-350'
9996                },
9997                ngOptions: 'item as item.name for item in field.items track by item.id',
9998                label: null
9999            }, userQualification.getList())
10000            .addField('qualification_year', 'text', {
10001                validators: {
10002                    required: false,
10003                    numericOnly: ''
10004                },
10005                options: {
10006                    placeholder: 'Год присвоения',
10007                    class: 'form__item width-170 margin_r_20',
10008                    maxlength: 4
10009                }
10010            })
10011            .addField('instructor_category', 'selectObject', {
10012                validators: {
10013                    required: false
10014                },
10015                options: {
10016                    defaultOption: 'Категория инструктора',
10017                    class: 'form__item form__item_select width-350 margin_r_40'
10018                },
10019                ngOptions: 'item as item.name for item in field.items track by item.id',
10020                label: null
10021            }, instructorCategories)
10022            .addField('instructor_doc', 'text', {
10023                validators: {
10024                    required: false,
10025                    numericOnly: ''
10026                },
10027                options: {
10028                    placeholder: 'Номер удостоверения',
10029                    class: 'form__item width-170'
10030                }
10031            })
10032            .addField('instructor_year', 'text', {
10033                validators: {
10034                    required: false,
10035                    numericOnly: ''
10036                },
10037                options: {
10038                    placeholder: 'Год присвоения',
10039                    class: 'form__item width-170 margin_r_20',
10040                    maxlength: 4
10041                }
10042            })
10043
10044            .addField('conductor_category', 'selectObject', {
10045                validators: {
10046                    required: false
10047                },
10048                options: {
10049                    defaultOption: 'Категория инструктора-проводника "Альпинизм и горный туризм"',
10050                    class: 'form__item form__item_select width-350 margin_r_40'
10051                },
10052                ngOptions: 'item as item.name for item in field.items track by item.id',
10053                label: null
10054            }, conductorCategories)
10055            .addField('conductor_doc', 'text', {
10056                validators: {
10057                    required: false
10058                },
10059                options: {
10060                    placeholder: 'Номер удостоверения',
10061                    class: 'form__item width-170'
10062                }
10063            })
10064            .addField('conductor_year', 'text', {
10065                validators: {
10066                    required: false,
10067                    numericOnly: ''
10068                },
10069                options: {
10070                    placeholder: 'Год присвоения',
10071                    class: 'form__item width-170 margin_r_20',
10072                    maxlength: 4
10073                }
10074            })
10075            .addField('instructor_job_seeker', 'checkbox', {
10076                validators: {
10077                    required: false
10078                },
10079                label: 'Ищу работу инструктора'
10080            })
10081            .addField('instructor_period_start', 'dateDropdowns', {
10082                validators: {
10083                    required: false
10084                },
10085                label: null,
10086                options: {
10087                      ngDisabled: function () {
10088                      },
10089                      ngChange: function(){
10090                        console.log('test');
10091                      }
10092
10093                    }               
10094            })
10095            .addField('instructor_period_end', 'dateDropdowns', {
10096                validators: {
10097                    required: false
10098                },
10099                label: null
10100            })
10101            .addField('judge_qualification_year', 'text', {
10102                validators: {
10103                    required: false,
10104                    numericOnly: ''
10105                },
10106                options: {
10107                    placeholder: 'Год присвоения',
10108                    class: 'form__item width-170 margin_r_20',
10109                    maxlength: 4
10110                }
10111            })
10112            .addField('judge_qualification_value', 'selectObject', {
10113                validators: {
10114                    required: false
10115                },
10116                options: {
10117                    defaultOption: 'Судейская квалификация',
10118                    class: 'form__item form__item_select width-170'
10119                },
10120                ngOptions: 'item as item.name for item in field.items track by item.id',
10121                label: null
10122            }, vm.achievements_value.judge_qualification)
10123            .addField('coach_qualification_year', 'text', {
10124                validators: {
10125                    required: false,
10126                    numericOnly: ''
10127                },
10128                options: {
10129                    placeholder: 'Год присвоения',
10130                    class: 'form__item width-170 margin_r_20',
10131                    maxlength: 4
10132                }
10133            })
10134            .addField('coach_qualification_value', 'selectObject', {
10135                validators: {
10136                    required: false
10137                },
10138                options: {
10139                    defaultOption: 'Тренерская квалификация',
10140                    class: 'form__item form__item_select width-170'
10141                },
10142                ngOptions: 'item as item.name for item in field.items track by item.id',
10143                label: null
10144            }, vm.achievements_value.coach_qualification)
10145            .addField('champion_russia_year', 'text', {
10146                validators: {
10147                    required: false,
10148                    numericOnly: ''
10149                },
10150                options: {
10151                    placeholder: 'Год присвоения',
10152                    class: 'form__item width-170 margin_r_20',
10153                    maxlength: 4
10154                }
10155            })
10156            .addField('champion_russia_value', 'selectObject', {
10157                validators: {
10158                    required: false
10159                },
10160                options: {
10161                    defaultOption: 'Чемпион России',
10162                    class: 'form__item form__item_select width-170'
10163                },
10164                ngOptions: 'item as item.name for item in field.items track by item.id',
10165                label: null
10166            }, vm.achievements_value.champion_russia)
10167            .addField('world_champion_year', 'text', {
10168                validators: {
10169                    required: false,
10170                    numericOnly: ''
10171                },
10172                options: {
10173                    placeholder: 'Год присвоения',
10174                    class: 'form__item width-170 margin_r_20',
10175                    maxlength: 4
10176                }
10177            })
10178            .addField('world_champion_value', 'selectObject', {
10179                validators: {
10180                    required: false
10181                },
10182                options: {
10183                    defaultOption: 'Чемпион мира',
10184                    class: 'form__item form__item_select width-170'
10185                },
10186                ngOptions: 'item as item.name for item in field.items track by item.id',
10187                label: null
10188            }, vm.achievements_value.world_champion)
10189            .addField('european_champion_year', 'text', {
10190                validators: {
10191                    required: false,
10192                    numericOnly: ''
10193                },
10194                options: {
10195                    placeholder: 'Год присвоения',
10196                    class: 'form__item width-170 margin_r_20',
10197                    maxlength: 4
10198                }
10199            })
10200            .addField('european_champion_value', 'selectObject', {
10201                validators: {
10202                    required: false
10203                },
10204                options: {
10205                    defaultOption: 'Чемпион Европы',
10206                    class: 'form__item form__item_select width-170'
10207                },
10208                ngOptions: 'item as item.name for item in field.items track by item.id',
10209                label: null
10210            }, vm.achievements_value.european_champion)
10211            .addField('russian_cup_year', 'text', {
10212                validators: {
10213                    required: false,
10214                    numericOnly: ''
10215                },
10216                options: {
10217                    placeholder: 'Год присвоения',
10218                    class: 'form__item width-170 margin_r_20',
10219                    maxlength: 4
10220                }
10221            })
10222            .addField('russian_cup_value', 'selectObject', {
10223                validators: {
10224                    required: false
10225                },
10226                options: {
10227                    defaultOption: 'Обладатель Кубка России',
10228                    class: 'form__item form__item_select width-170'
10229                },
10230                ngOptions: 'item as item.name for item in field.items track by item.id',
10231                label: null
10232            }, vm.achievements_value.russian_cup)
10233
10234            .addField('european_cup_year', 'text', {
10235                validators: {
10236                    required: false,
10237                    numericOnly: ''
10238                },
10239                options: {
10240                    placeholder: 'Год присвоения',
10241                    class: 'form__item width-170 margin_r_20',
10242                    maxlength: 4
10243                }
10244            })
10245            .addField('european_cup_value', 'selectObject', {
10246                validators: {
10247                    required: false
10248                },
10249                options: {
10250                    defaultOption: 'Обладатель Кубка Европы',
10251                    class: 'form__item form__item_select width-170'
10252                },
10253                ngOptions: 'item as item.name for item in field.items track by item.id',
10254                label: null
10255            }, vm.achievements_value.european_cup)
10256
10257            .addField('world_cup_year', 'text', {
10258                validators: {
10259                    required: false,
10260                    numericOnly: ''
10261                },
10262                options: {
10263                    placeholder: 'Год присвоения',
10264                    class: 'form__item width-170 margin_r_20',
10265                    maxlength: 4
10266                }
10267            })
10268            .addField('world_cup_value', 'selectObject', {
10269                validators: {
10270                    required: false
10271                },
10272                options: {
10273                    defaultOption: 'Обладатель Кубка мира',
10274                    class: 'form__item form__item_select width-170'
10275                },
10276                ngOptions: 'item as item.name for item in field.items track by item.id',
10277                label: null
10278            }, vm.achievements_value.world_cup)
10279            .addField('rescue_in_mountains_year', 'text', {
10280                validators: {
10281                    required: false,
10282                    numericOnly: ''
10283                },
10284                options: {
10285                    placeholder: 'Год присвоения',
10286                    class: 'form__item width-170 margin_r_20',
10287                    maxlength: 4
10288                }
10289            })
10290            .addField('rescue_in_mountains_value', 'text', {
10291                validators: {
10292                    required: false
10293                },
10294                options: {
10295                    placeholder: 'Номер удостоверения',
10296                    class: 'form__item width-170'
10297                }
10298            })
10299            .addField('rescue_squad_year', 'text', {
10300                validators: {
10301                    required: false,
10302                    numericOnly: ''
10303              
10303  },
10304                options: {
10305                    placeholder: 'Год присвоения',
10306                    class: 'form__item width-170 margin_r_20',
10307                    maxlength: 4
10308                }
10309            })
10310            .addField('rescue_squad_value', 'text', {
10311                validators: {
10312                    required: false
10313                },
10314                options: {
10315                    placeholder: 'Номер удостоверения',
10316                    class: 'form__item width-170'
10317                }
10318            })
10319            .addField('mountain_guide_year', 'text', {
10320                validators: {
10321                    required: false,
10322                    numericOnly: ''
10323                },
10324                options: {
10325                    placeholder: 'Год присвоения',
10326                    class: 'form__item width-170 margin_r_20',
10327                    maxlength: 4
10328                }
10329            })
10330            .addField('mountain_guide_value', 'text', {
10331                validators: {
10332                    required: false
10333                },
10334                options: {
10335                    placeholder: 'Номер удостоверения',
10336                    class: 'form__item width-170'
10337                }
10338            })
10339            .addField('snow_leopard_year', 'text', {
10340                validators: {
10341                    required: false,
10342                    numericOnly: ''
10343                },
10344                options: {
10345                    placeholder: 'Год присвоения',
10346                    class: 'form__item width-170 margin_r_20',
10347                    maxlength: 4
10348                }
10349            })
10350            .addField('snow_leopard_value', 'text', {
10351                validators: {
10352                    required: false
10353                },
10354                options: {
10355                    placeholder: 'Номер удостоверения',
10356                    class: 'form__item width-170'
10357                }
10358            })
10359                        .addField('snow_leopard_ru_year', 'text', {
10360                validators: {
10361                    required: false,
10362                    numericOnly: ''
10363                },
10364                options: {
10365                    placeholder: 'Год присвоения',
10366                    class: 'form__item width-170 margin_r_20',
10367                    maxlength: 4
10368                }
10369            })
10370            .addField('snow_leopard_ru_value', 'text', {
10371                validators: {
10372                    required: false
10373                },
10374                options: {
10375                    placeholder: 'Номер удостоверения',
10376                    class: 'form__item width-170'
10377                }
10378            })
10379            .addField('climbing_everest_year', 'text', {
10380                validators: {
10381                    required: false,
10382                    numericOnly: ''
10383                },
10384                options: {
10385                    placeholder: 'Год восхождения',
10386                    class: 'form__item width-170 margin_r_20',
10387                    maxlength: 4
10388                }
10389            })
10390            .addField('user_award_golden_ice_axe_ru_year', 'text', {
10391                validators: {
10392                    required: false,
10393                    numericOnly: ''
10394                },
10395                options: {
10396                    placeholder: 'Год присвоения',
10397                    class: 'form__item width-170 margin_r_20',
10398                    maxlength: 4
10399                }
10400            })
10401            .addField('user_award_golden_ice_axe_ru_status', 'selectObject', {
10402                validators: {
10403                    required: false
10404                },
10405                options: {
10406                    defaultOption: 'Статус',
10407                    class: 'form__item form__item_select width-170'
10408                },
10409                ngOptions: 'item as item.name for item in field.items track by item.id',
10410                label: null
10411            }, userAward.status)
10412            .addField('user_award_golden_ice_axe_ru_type', 'hidden', {})
10413            .addField('user_award_steel_angel_year', 'text', {
10414                validators: {
10415                    required: false,
10416                    numericOnly: ''
10417                },
10418                options: {
10419                    placeholder: 'Год присвоения',
10420                    class: 'form__item width-170 margin_r_20',
10421                    maxlength: 4
10422                }
10423            })
10424            .addField('user_award_golden_ice_axe_year', 'text', {
10425                validators: {
10426                    required: false,
10427                    numericOnly: ''
10428                },
10429                options: {
10430                    placeholder: 'Год присвоения',
10431                    class: 'form__item width-170 margin_r_20',
10432                    maxlength: 4
10433                }
10434            })
10435            .addField('user_award_golden_ice_axe_status', 'selectObject', {
10436                validators: {
10437                    required: false
10438                },
10439                options: {
10440                    defaultOption: 'Статус',
10441                    class: 'form__item form__item_select width-170'
10442                },
10443                ngOptions: 'item as item.name for item in field.items track by item.id',
10444                label: null
10445            }, userAward.status)
10446            .addField('user_award_golden_ice_axe_type', 'hidden', {})
10447            .addField('user_award_steel_angel_year', 'text', {
10448                validators: {
10449                    required: false,
10450                    numericOnly: ''
10451                },
10452                options: {
10453                    placeholder: 'Год присвоения',
10454                    class: 'form__item width-170 margin_r_20',
10455                    maxlength: 4
10456                }
10457            })
10458            .addField('user_award_steel_angel_status', 'selectObject', {
10459                validators: {
10460                    required: false
10461                },
10462                options: {
10463                    defaultOption: 'Статус',
10464                    class: 'form__item form__item_select width-170'
10465                },
10466                ngOptions: 'item as item.name for item in field.items track by item.id',
10467                label: null
10468            }, userAward.status)
10469            .addField('user_award_steel_angel_type', 'hidden', {})
10470            .addField('qualification_ice_climbing', 'text', {
10471                validators: {
10472                    required: false
10473                },
10474                options: {
10475                    placeholder: 'Ледолазание'
10476                }
10477            })
10478            .addField('qualification_rock_climbing', 'text', {
10479                validators: {
10480                    required: false
10481                },
10482                options: {
10483                    placeholder: 'Скалолазание'
10484                }
10485            })
10486            .addField('qualification_ski_mountaineering', 'text', {
10487                validators: {
10488                    required: false
10489                },
10490                options: {
10491                    placeholder: 'Ски-альпинизм'
10492                }
10493            })
10494            .addField('qualification_skyrunning', 'text', {
10495                validators: {
10496                    required: false
10497                },
10498                options: {
10499                    placeholder: 'Скайраннинг'
10500                }
10501            })
10502            .addField('qualification_mountain_tourism', 'text', {
10503                validators: {
10504                    required: false
10505                },
10506                options: {
10507                    placeholder: 'Горный туризм'
10508                }
10509            })
10510            .addField('qualification_skiing', 'text', {
10511                validators: {
10512                    required: false
10513                },
10514                options: {
10515                    placeholder: 'Горные лыжи'
10516                }
10517            })
10518            .addField('avatar', 'imageUpload', {
10519                validators: {
10520                    required: false
10521                },
10522                label: 'Загрузить изображение',
10523                uploader: {
10524                    url: Routing.generate('api_upload_post_avatar', {thumb: 'avatar_relative'}),
10525                    autoUpload: true,
10526                    removeAfterUpload: true,
10527                    onSuccessItem: function (item, response) {
10528                        vm.form.avatar = response;
10529                    }
10530                }
10531            })
10532            .addField('country', 'uiSelect', {
10533                validators: {
10534                    required: true
10535                },
10536                options: {
10537                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
10538                    class: 'form__ui-select width-350'
10539                },
10540                uiSelectOptions: {
10541                    matchTitle: '{{ $select.selected.name }} ',
10542                    choicesTitle: '{{ item.name }}',
10543                    match: {
10544                        placeholder: 'Страна',
10545                        allowClear: true
10546                    },
10547                    choices: {
10548                        repeat: 'item in field.items track by item.id',
10549                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Country", "country")',
10550                        refreshDelay: 0
10551                    },
10552                    refreshAutoComplete: autocomplete.refreshAutoComplete,
10553                    onSelect: function (item) {
10554                        if (item) {
10555                            vm.autoCompleteSelect.country = item.id;
10556                            vm.autoCompleteSelect.region = null;
10557                            vm.autoCompleteSelect.city = null;
10558                            vm.form.country = item;
10559
10560                            vm.formUserEdit.$fields.region.items = [];
10561                            vm.formUserEdit.$fields.city.items = [];
10562                        }
10563                    }
10564                },
10565                fieldData: {
10566                    name: 'country'
10567                }
10568            }, autocomplete.get('country'))
10569            .addField('region', 'uiTypeahead', {
10570                validators: {
10571                    required: true
10572                },
10573                label: null,
10574                options: {
10575                    class: 'form__item',
10576                    placeholder: 'Регион',
10577                    tabindex: 10,
10578                    uibTypeahead: "row as row.name for row in field.refreshAutoComplete($viewValue, 'Region')"
10579                },
10580                fieldData: {
10581                    clearBtn: true,
10582                    refreshAutoComplete: function (name, term) {
10583                        return autocomplete.refreshAutoComplete(name, term, null, vm.autoCompleteSelect)
10584                    }
10585                }
10586            })
10587            .addField('city', 'uiTypeahead', {
10588                validators: {
10589                    required: false
10590                },
10591                label: null,
10592                options: {
10593                    class: 'form__item',
10594                    placeholder: 'Населенный пункт',
10595                    uibTypeahead: "row as row.name for row in field.refreshAutoComplete($viewValue, 'KladrCity')"
10596                },
10597                fieldData: {
10598                    clearBtn: true,
10599                    refreshAutoComplete: function (name, term) {
10600                        if (angular.isObject(vm.form.region)) {
10601                            vm.autoCompleteSelect.region = vm.form.region.id;
10602                        } else {
10603                            vm.autoCompleteSelect.region = null;
10604                        }
10605
10606                        return autocomplete.refreshAutoComplete(name, term, null, vm.autoCompleteSelect)
10607                    }
10608                }
10609            })
10610            .addField('club', 'uiSelect', {
10611                validators: {
10612                    required: true
10613                },
10614                options: {
10615                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
10616                    class: 'form__ui-select width-400 margin_r_40'
10617                },
10618                uiSelectOptions: {
10619                    matchTitle: '{{ $select.selected.name }} ',
10620                    choicesTitle: '{{ item.name }}',
10621                    match: {
10622                        placeholder: 'Федерация альпинизма',
10623                        allowClear: true
10624                    },
10625                    choices: {
10626                        repeat: 'item in field.items track by item.id',
10627                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Club", "club")',
10628                        refreshDelay: 400
10629                    },
10630                    refreshAutoComplete: function(name, term, object) {
10631                        return autocomplete.refreshAutoComplete(name, term, object, {'subclub':'false'})
10632                    },
10633                    onSelect: function (item) {
10634                        vm.form.club = item;
10635                    },
10636                    onClear: function() {
10637                        return false;
10638                    }
10639                }
10640            }, autocomplete.get('club'))
10641            .addField('club_other', 'radioCollection', {
10642                radio: {
10643                    label: 'name'
10644                }
10645            }, vm.club_other_items);
10646
10647        return vm;
10648    }]);
10649
10650},{}],100:[function(require,module,exports){
10651'use strict';
10652
10653angular.module('far.profile')
10654.controller('EventsProfileController', ["$log", "$http", "$window", "$timeout", "$q", "pagination", function (
10655	$log,
10656	$http,
10657	$window,
10658	$timeout,
10659	$q,
10660	pagination
10661) {
10662	var vm = {
10663		constructor: constructor,
10664		pagination: pagination('events', {next: nextPage, itemsOnPage: 2}),
10665		type: null,
10666		filter: {
10667			period: 'all',
10668			eventData: null
10669		},
10670		userId: null,
10671		personalEvents: [],
10672		events: [],
10673		eventRequest: function () {
10674			$window.location.href = Routing.generate('event_request', {type: vm.eventType});
10675		}
10676	};
10677
10678	function constructor(userId, type) {
10679		vm.userId = userId;
10680		vm.type = type;
10681
10682		vm.pagination.clear();
10683	}
10684
10685	function nextPage(page, count) {
10686        var eventData = {};
10687
10688        if (vm.filter.eventData) {
10689            eventData[vm.filter.eventData] = true;
10690        }
10691
10692		return $http.get(Routing.generate('api_event_get_eventplans', {
10693			id: vm.userId,
10694			type: vm.type,
10695			offset: (page - 1) * count,
10696			limit: count,
10697			period: vm.filter.period,
10698			event_data: eventData
10699		})).then(function(response) {
10700			var items = [];
10701			vm.totalPages = Math.ceil(response.headers('X-Total-Count') / count);
10702
10703			angular.forEach(response.data, function(item) {
10704				items.push(item);
10705			});
10706
10707			return items;
10708		}).catch(function(response) {
10709			$log.error(response);
10710			return $q.reject(response);
10711		});
10712	}
10713	
10714	return vm;
10715}]);
10716
10717},{}],101:[function(require,module,exports){
10718 "use strict";
10719
10720angular
10721    .module("far.profile")
10722    .controller(
10723        "ProfileMembershipController",
10724        ["$scope", "$window", "$log", "$http", "form", "autocomplete", "User", "formsUtils", "http", function (
10725            $scope,
10726            $window,
10727            $log,
10728            $http,
10729            form,
10730            autocomplete,
10731            User,
10732            formsUtils,
10733            http
10734        ) {
10735			var organizations=autocomplete.refreshAutoComplete("", "Clubs", "club");
10736			console.log(autocomplete.refreshAutoComplete("d", "Clubs", "club"));
10737
10738            var vm = {
10739                progress: true,
10740                submitted: false,
10741                show_error: false,
10742                club_required: true,
10743                club_checkbox: false,
10744                max: null,
10745                form: {},
10746                autoCompleteSelect: {
10747                    country: null,
10748                    region: null,
10749                    city: null,
10750                },
10751                submit: submit,
10752                fields: form("ProfileMembership"),
10753                constructor: constructor,
10754                counter: 1,
10755                getCounter: getCounter,
10756                club_other_items:[  {
10757                id: 0,
10758                name: 'Отдать голос представителю региональной федерации'
10759             },
10760            // {
10761            //     id: 1,
10762            //     name: 'Отдать голос президенту ФАР, во время голосования Ваш голос будет учтен в ФАиС Москвы'
10763            // },
10764            {
10765                id: 2,
10766                name: 'Принимает участие в конференции лично'
10767            }],
10768                prev_club_id: null,
10769                validationExpired: true,
10770		 organizations:organizations,
10771
10772		};
10773
10774	            vm.fields
10775	 .addField('club', 'selectObject', {
10776                validators: {
10777                    required: true
10778                },
10779                options: {
10780                    defaultOption: '',
10781                    class: 'form__item form__item_select width-350',
10782                    ngChange: 'field.ngChange(model)'
10783                },
10784                ngOptions: 'item as item.name for item in field.items track by item.id',
10785                fieldData: {
10786                    ngChange: function (item) {
10787			console.log(vm.nextyear,vm.validationExpired);
10788			   vm.form.club = item;
10789                                if (
10790                                    item &&
10791                                    item.fee &&
10792				    vm.prev_club_id != item.id
10793 
10794                                ) {
10795                                    vm.form.local_fee = +item.fee;
10796                                } else {
10797				if (vm.validationExpired) {
10798                		             vm.form.local_fee = +item.fee;
10799                        		}
10800				else if ((new Date().getMonth()=='10' ||new Date().getMonth()=='11') && !vm.nextyear){
10801			
10802					  vm.form.local_fee = +item.fee;
10803                	  	  }
10804				else
10805
10806                                    vm.form.local_fee = 0;
10807                                }
10808                                vm.form.total_price =
10809                                    vm.form.price + vm.form.local_fee;                      
10810                    }
10811                }
10812            }, vm.organizations)
10813
10814                      
10815
10816                // .addField('club_checkbox', 'checkbox', {
10817                //     validators: {
10818                //         required: false
10819                //     },
10820                //     options: {
10821                //         ngChecked: function () {
10822                //             if ( vm.club_checkbox ) {
10823                //                 vm.form.club = null;
10824                //                 vm.club_required = false;
10825                //             } else {
10826                //                 vm.club_required = true;
10827                //             }
10828
10829                //             return vm.club_checkbox;
10830                //         }
10831                //     },
10832                //     label: 'Я не состою ни в одной организации'
10833                // })
10834                .addField(
10835                    "club_other",
10836                    "radioCollection",
10837                    {
10838                        radio: {
10839                            label: "name",
10840                        },
10841                    },
10842                    vm.club_other_items
10843                )
10844                .addField("phone", "text", {
10845                    validators: {
10846                        required: true,
10847                    },
10848                    options: {
10849                        placeholder: "Телефон",
10850                    },
10851                })
10852                .addField("email", "text", {
10853                    validators: {
10854                        required: true,
10855                    },
10856                    options: {
10857                        placeholder: "E-mail",
10858                    },
10859                })
10860                .addField("last_name", "text", {
10861                    validators: {
10862                        required: true,
10863                    },
10864                    options: {
10865                        placeholder: "Фамилия",
10866                    },
10867                })
10868                .addField("first_name", "text", {
10869                    validators: {
10870                        required: true,
10871                    },
10872                    options: {
10873                        placeholder: "Имя",
10874                    },
10875                })
10876                .addField("middle_name", "text", {
10877                    validators: {
10878                        required: false,
10879                    },
10880                    options: {
10881                        placeholder: "Отчество",
10882                    },
10883                })
10884                .addField("counter", "text", {
10885                    validators: {
10886                        required: true,
10887                        numericOnly: "",
10888                    },
10889                    options: {
10890                        placeholder: "1",
10891                        class: "form-counter__input",
10892                        maxlength: 2,
10893                    },
10894                })
10895                .addField(
10896                    "country",
10897                    "uiSelect",
10898                    {
10899                        validators: {
10900                            required: true,
10901                        },
10902                        options: {
10903                            onSelect:
10904                                "field.uiSelectOptions.onSelect($item, $model)",
10905                            class: "form__ui-select width-350",
10906                        },
10907                        uiSelectOptions: {
10908                            matchTitle: "{{ $select.selected.name }} ",
10909                            choicesTitle: "{{ item.name }}",
10910                            match: {
10911                                placeholder: "Страна",
10912                                allowClear: true,
10913                            },
10914                            choices: {
10915                                repeat: "item in field.items track by item.id",
10916                                refresh:
10917                                    'field.uiSelectOptions.refreshAutoComplete($select.search, "Country", "country")',
10918                                refreshDelay: 0,
10919                            },
10920                            refreshAutoComplete:
10921                                autocomplete.refreshAutoComplete,
10922                            onSelect: function (item) {
10923                                if (item) {
10924                                    vm.autoCompleteSelect.country = item.id;
10925                                    vm.autoCompleteSelect.region = null;
10926                                    vm.autoCompleteSelect.city = null;
10927
10928                                    vm.form.country = item;
10929
10930                                    vm.fields.$fields.region.items = [];
10931                                    vm.fields.$fields.city.items = [];
10932                                }
10933                            },
10934                        },
10935                        fieldData: {
10936                            name: "country",
10937                        },
10938                    },
10939                    autocomplete.get("country")
10940                )
10941                .addField("region", "uiTypeahead", {
10942                    validators: {
10943                        required: false,
10944                    },
10945                    label: null,
10946                    options: {
10947                        class: "form__item",
10948                        placeholder: "Регион",
10949                        tabindex: 10,
10950                        uibTypeahead:
10951                            "row as row.name for row in field.refreshAutoComplete($viewValue, 'KladrRegion')",
10952                    },
10953                    fieldData: {
10954                        clearBtn: true,
10955                        refreshAutoComplete: function (name, term) {
10956                            return autocomplete.refreshAutoComplete(
10957                                name,
10958                                term,
10959                                null,
10960                                vm.autoCompleteSelect
10961                            );
10962                        },
10963                    },
10964                })
10965                .addField("city", "uiTypeahead", {
10966                    validators: {
10967                        required: false,
10968                    },
10969                    label: null,
10970                    options: {
10971                        class: "form__item",
10972                        placeholder: "Населенный пункт",
10973                        uibTypeahead:
10974                            "row as row.name for row in field.refreshAutoComplete($viewValue, 'KladrCity')",
10975                    },
10976                    fieldData: {
10977                        clearBtn: true,
10978                        refreshAutoComplete: function (name, term) {
10979                            if (angular.isObject(vm.form.region)) {
10980                                vm.autoCompleteSelect.region =
10981                                    vm.form.region.id;
10982                            } else {
10983                                vm.autoCompleteSelect.region = null;
10984                            }
10985
10986                            return autocomplete.refreshAutoComplete(
10987                                name,
10988                                term,
10989                                null,
10990                                vm.autoCompleteSelect
10991                            );
10992                        },
10993                    },
10994                })
10995                .addField("post_index", "text", {
10996                    validators: {
10997                        required: false,
10998                        numericOnly: "",
10999                    },
11000                    options: {
11001                        placeholder: "Индекс",
11002                    },
11003                })
11004                .addField("address", "text", {
11005                    validators: {
11006                        required: false,
11007                    },
11008                    options: {
11009                        placeholder: "Улица",
11010                    },
11011                })
11012                .addField("house", "text", {
11013                    validators: {
11014                        required: false,
11015                    },
11016                    options: {
11017                        placeholder: "Дом",
11018                        class: "form__item width-80 margin_r_20",
11019                    },
11020                })
11021                .addField("building", "text", {
11022                    validators: {
11023                        required: false,
11024                    },
11025                    options: {
11026                        placeholder: "Кор.",
11027                        class: "form__item width-80 margin_r_20",
11028                    },
11029                })
11030                .addField("apartment", "text", {
11031                    validators: {
11032                        required: false,
11033                    },
11034                    options: {
11035                        placeholder: "Кв.",
11036                        class: "form__item width-80",
11037                    },
11038                });
11039
11040            function submit() {
11041                vm.submitted = true;
11042                vm.show_error = true;
11043
11044                if (!$scope.membershipForm.$valid) {
11045                    vm.submitted = false;
11046
11047                    return false;
11048                }
11049
11050                if (!vm.club_checkbox) {
11051                    vm.form.club_other = undefined;
11052                }
11053                 vm.form.achievements = vm.form.achievements.map(function (
11054                     achievement
11055                 ) {
11056                     return {
11057                        user: vm.form.id,
11058                         type: achievement.type.id,
11059                         value: achievement.value,
11060                         year: achievement.year,
11061                     };
11062                 });
11063                 vm.form.club_next = vm.form.club ? vm.form.club.id : null;
11064
11065                // не меняем клуб до оплаты
11066
11067		if (
11068                   vm.form.total_price > 0 &&
11069                    vm.form.club.id !== vm.prev_club_id
11070                ) {
11071			
11072                   vm.form.club_next = vm.form.club ? vm.form.club.id : null;
11073                    if (vm.prev_club_id) {
11074			console.log(vm.prev_club_id);
11075                        vm.form.club = vm.prev_club_id;
11076                    } else {
11077                        vm.form.club = null;
11078                    }
11079                }
11080
11081                vm.form.save().then(
11082                    function () {
11083			console.log(vm.form.total_price);
11084                        if (vm.form.total_price == 0) {
11085                            return;
11086                        }
11087			console.log(vm.form.id,vm.form.counter,vm.form.club_next);
11088                        $http
11089                            .post(Routing.generate("api_post_order"), {
11090                                user: vm.form.id,
11091                                club_next: vm.form.club_next,
11092                            })
11093                            .then(
11094                                function (response) {
11095				console.log(response.data.url);
11096                                    $window.location.href = response.data.url;
11097                                },
11098                                function errorCallback(response) {
11099                                    response =
11100                                        http.authenticationListener(response);
11101
11102                                    $log.error(response);
11103                                }
11104                            );
11105                    },
11106                    function errorCallback(response) {
11107                        response = http.authenticationListener(response);
11108
11109                        vm.submitted = false;
11110
11111                        $log.error(response);
11112                    }
11113                );
11114            }
11115
11116            function constructor(
11117                user,
11118                price,
11119                max,
11120                validationExpired,
11121                federationFee,
11122                userClubId,
11123		nextyear
11124            ) {
11125                vm.form = User.get(user, function () {
11126                    vm.form.counter = 1;
11127
11128                    vm.form.confirmation = true;
11129                    vm.max = max;
11130			vm.nextyear=nextyear;
11131
11132                    vm.club_checkbox = false;
11133                    vm.validationExpired = !!validationExpired;
11134
11135                    if (validationExpired) {
11136                        vm.form.price = +price;		
11137
11138                    }else if ((new Date().getMonth()=='10' || new Date().getMonth()=='11') && !nextyear){
11139			 vm.form.price = +price;
11140                	    }
11141
11142			 else {
11143                        vm.form.price = 0;
11144                    }
11145
11146                    if (federationFee) {
11147                        if (validationExpired) {
11148                            vm.form.local_fee = federationFee;
11149                        }
11150			else if ((new Date().getMonth()=='10' ||new Date().getMonth()=='11') && !nextyear){
11151			
11152			 vm.form.local_fee = federationFee;
11153                	    }
11154
11155			else {
11156                            vm.form.local_fee = 0;
11157                        }
11158                    } else {
11159                        vm.form.local_fee = 0;
11160                    }
11161
11162                    vm.form.total_price = vm.form.price + vm.form.local_fee;
11163
11164                    vm.prev_club_id = userClubId;
11165
11166                    // if ( vm.form.club_other ) {
11167                    //     vm.club_checkbox = true;
11168                    // } else {
11169                    //     vm.form.club_other = vm.club_other_items[0].id;
11170                    // }
11171
11172                    vm.progress = false;
11173                });
11174            }
11175
11176            function counter(type) {
11177                // if (type == 1) {
11178                //     if (vm.form.counter < vm.max) {
11179                //         vm.form.counter++;
11180                //     }
11181                // } else {
11182                //     if (vm.form.counter > 1) {
11183                //         vm.form.counter--;
11184                //     }
11185                // }
11186                return 1;
11187            }
11188
11189            function getCounter() {
11190               // return (
11191                 //   vm.form.counter +
11192                //    " " +
11193                 //   formsUtils.numEnding(vm.form.counter, [
11194                   //     "год",
11195                    //    "года",
11196                    //    "лет",
11197                   // ])
11198                //);
11199	    return "01.01."+new Date().getFullYear()+"-31.12.2022";
11200            }
11201
11202            return vm;
11203        }]
11204    );
11205
11206},{}],102:[function(require,module,exports){
11207'use strict';
11208
11209angular.module('far.profile')
11210    .controller('ProfileNoticeController', ["$rootScope", "Notice", "softdeleteable", "pagination", function ($rootScope, Notice, softdeleteable, pagination) {
11211        var vm = {
11212            progress: true,
11213            submitted: false,
11214            user: null,
11215            notices: [],
11216            notices_hide: [],
11217            type: 0,
11218            pagination: pagination('notice', {next: nextPage, itemsOnPage: 20}),
11219            constructor: function (user) {
11220                vm.user = user;
11221                vm.pagination.clear()
11222            },
11223            delete: function (notice) {
11224                softdeleteable.delete(notice)
11225            },
11226            restore: function (notice) {
11227                softdeleteable.restore(notice)
11228            },
11229            check: function (notice) {
11230                return softdeleteable.check(notice)
11231            },
11232            reload: function() {
11233                vm.notices = [];
11234                vm.pagination.clear();
11235            }
11236        };
11237
11238        function nextPage(page, count, type) {
11239            return Notice.getByUser(vm.user, ((page - 1) * count), count, function (response) {
11240                vm.totalPages = Math.ceil(response.headers('X-Total-Count') / count);
11241
11242                response.data.forEach(function (item) {
11243                    vm.notices.push(item)
11244                });
11245
11246                softdeleteable.setModel(Notice);
11247
11248                vm.progress = false;
11249
11250                return vm.notices;
11251            }, vm.type);
11252        }
11253
11254        return vm;
11255    }]);
11256
11257},{}],103:[function(require,module,exports){
11258"use strict";
11259angular.module('far.profile')
11260    .controller('ProfileSidebarController', ["form", "userSendings", "$timeout", "$http", "$filter", function (form, userSendings, $timeout, $http, $filter) {
11261
11262        var vm = {
11263            sidebarFrom: form('sidebarFrom'),
11264            isAdmin : false,
11265            userId : 0,
11266            progress : false,
11267            progressStack : [],
11268            sendingsData: null,
11269            show_address_modal: false,
11270            address_modal_text: '',
11271            address_modal_title: 'Адрес доставки',
11272            address_modal_btn_text: '',
11273            show_request_sent_popup: false,
11274            init: function(userId, isAdmin) {
11275                vm.isAdmin = isAdmin;
11276                vm.userId = userId;
11277                vm.pushProgress();
11278                vm.sendingsData = userSendings.get(userId, function() {
11279                    vm.popProgress();
11280                    vm.updateIsMemberCardSentLabel();
11281                });
11282            },
11283            showRequestSentPopup: function() {
11284                vm.show_request_sent_popup = true;
11285                vm.show_address_modal = false;
11286                return false;
11287            },
11288            pushProgress : function() {
11289                vm.progressStack.push(1);
11290                vm.progress = true;
11291            },
11292            popProgress : function() {
11293                vm.progressStack.pop();
11294                if (vm.progressStack.length == 0) {
11295                    vm.progress = false;
11296                }
11297            },
11298            updateIsMemberCardSentLabel: function() {
11299                var label = 'Карта отправлена';
11300                if (vm.sendingsData && vm.sendingsData.is_member_card_sent) {
11301                    label += ' (' + vm.sendingsData.member_card_sent + ')';
11302                }
11303                vm.sidebarFrom.$fields.isMemberCardSent.label = label;
11304            },
11305            showAddressPopup: function() {
11306                if (vm.sendingsData.full_address) {
11307                    vm.address_modal_text = vm.sendingsData.full_address;
11308                    vm.address_modal_btn_text = 'Уточнить адрес';
11309                } else {
11310                    vm.address_modal_text = 'В вашем профиле не заполнен адрес. Заполните его пожалуйста.';
11311                    vm.address_modal_btn_text = 'Заполнить адрес';
11312                }
11313                vm.show_address_modal = true;
11314            },
11315            sendMemberCardAndSticker: function() {
11316                vm.sendingsData.send_member_card_and_sticker = true;
11317                vm.pushProgress();
11318                vm.sendingsData.saveSendMemberCardAndSticker(function() {
11319                    vm.popProgress();
11320                    vm.showAddressPopup();
11321                });
11322            },
11323            sendSticker: function() {
11324                vm.sendingsData.send_sticker = true;
11325                vm.pushProgress();
11326                vm.sendingsData.saveSendSticker(function() {
11327                    vm.popProgress();
11328                    vm.showAddressPopup();
11329                });
11330            },
11331
11332        };
11333
11334        vm.sidebarFrom.addField('isMemberCardSent', 'checkbox', {
11335            label: '',
11336            options: {
11337                ngChange: function () {
11338                    $timeout(function(){
11339                        vm.pushProgress();
11340                        vm.sendingsData.saveMemberCardSent(function() {
11341                            vm.popProgress();
11342                            vm.updateIsMemberCardSentLabel();
11343                        });
11344                    });
11345                }
11346            }
11347        });
11348
11349        vm.updateIsMemberCardSentLabel();
11350
11351        vm.sidebarFrom.addField('isMemberCardReceived', 'checkbox', {
11352            label: 'Карта получена',
11353            options: {
11354                ngChange: function () {
11355                    $timeout(function(){
11356                        vm.pushProgress();
11357                        vm.sendingsData.saveMemberCardReceived(function() {
11358                            vm.popProgress();
11359                        });
11360                    });
11361                }
11362            }
11363        });
11364
11365        return vm;
11366    }]);
11367
11368},{}],104:[function(require,module,exports){
11369require('./profile.module');
11370require('./controllers/ascent.controller');
11371require('./controllers/events.controller');
11372require('./controllers/edit.controller');
11373require('./controllers/membership.controller');
11374require('./controllers/notice.controller');
11375require('./controllers/discharge.controller');
11376require('./controllers/sidebar.controller');
11377
11378},{"./controllers/ascent.controller":97,"./controllers/discharge.controller":98,"./controllers/edit.controller":99,"./controllers/events.controller":100,"./controllers/membership.controller":101,"./controllers/notice.controller":102,"./controllers/sidebar.controller":103,"./profile.module":105}],105:[function(require,module,exports){
11379'use strict';
11380
11381require('../core/core');
11382require('../../modules/pagination/pagination');
11383require('../../modules/forms/forms');
11384
11385require('../../models/ascent/ascents');
11386require('../../models/ascent/ascentTypes');
11387require('../../models/user/user');
11388require('../../models/user/userSendings');
11389require('../../models/user/userQualification');
11390require('../../models/user/userClub');
11391require('../../models/user/userAward');
11392require('../../models/user/userRelation');
11393require('../../models/mountains/regions');
11394require('../../models/mountains/peaks');
11395require('../../models/mountains/routes');
11396require('../../models/notice/notice');
11397
11398require('../../forms/ascentEditForm');
11399
11400require('../../helpers/show-modal-message/show-modal-message');
11401
11402angular.module('far.profile', [
11403	'ngTouch',
11404	'angularFileUpload',
11405	'ui.select',
11406	'ui.bootstrap',
11407	'dekky.pagination',
11408	'dekky.forms',
11409	'far.models.ascents',
11410	'far.models.ascentTypes',
11411	'far.models.user',
11412	'far.models.userSendings',
11413	'far.models.userRelation',
11414	'far.models.userQualification',
11415	'far.models.userClub',
11416	'far.models.userAward',
11417	'far.models.mountains.regions',
11418	'far.models.mountains.peaks',
11419	'far.models.mountains.routes',
11420	'far.models.notice',
11421	'far.core',
11422	'far.forms.ascentEditForm',
11423	'far.helpers.showModalMessage'
11424]).value('formsConfig', {
11425	theme: '/dekky.forms/themes/far'
11426});
11427
11428},{"../../forms/ascentEditForm":140,"../../helpers/show-modal-message/show-modal-message":167,"../../models/ascent/ascentTypes":183,"../../models/ascent/ascents":185,"../../models/mountains/peaks":213,"../../models/mountains/regions":214,"../../models/mountains/routes":217,"../../models/notice/notice":220,"../../models/user/user":228,"../../models/user/userAward":230,"../../models/user/userClub":231,"../../models/user/userQualification":233,"../../models/user/userRelation":234,"../../models/user/userSendings":235,"../../modules/forms/forms":244,"../../modules/pagination/pagination":341,"../core/core":38}],106:[function(require,module,exports){
11429'use strict';
11430
11431angular.module('far.project').controller('ProjectReportController', ["$rootScope", "$window", "projectReportForm", "Project", "ProjectReport", "$scope", "FileUploader", function ($rootScope, $window, projectReportForm, Project, ProjectReport, $scope, FileUploader) {
11432    var vm = {
11433        progress: true,
11434        submitted: false,
11435        form: {},
11436        event: {},
11437        requestController: {},
11438        users: [],
11439        fields: projectReportForm,
11440        eventType: null,
11441        eventUserTypes: {},
11442        init: function (eventId, eventReportEdit) {
11443            if (eventReportEdit) {
11444                vm.form = ProjectReport.get(eventId, vm.eventUserTypes, function () {
11445                    if (vm.form.documents_files.length > 0) {
11446                        vm.form.documents_files.forEach(function (serverFile) {
11447                            var newFile = new FileUploader.FileItem(vm.fields.$fields.documentsFiles.uploader, {
11448                                lastModifiedDate: new Date(),
11449                                size: 1e6,
11450                                name: serverFile.original_name
11451                            });
11452
11453                            newFile.progress = 100;
11454                            newFile.isUploaded = true;
11455                            newFile.isSuccess = true;
11456                            newFile.serverData = angular.merge({}, serverFile);
11457
11458                            vm.fields.$fields.documentsFiles.uploader.queue.push(newFile);
11459                        });
11460                    }
11461
11462                    vm.progress = false;
11463                });
11464            } else {
11465                vm.form = ProjectReport.new({
11466                    event_id: eventId
11467                }, vm.eventUserTypes);
11468
11469                var usersWatch = $rootScope.$watch(function () {
11470                    return vm.requestController.users.length;
11471                }, function (length) {
11472                    if (length > 0) {
11473                        vm.requestController.users.forEach(function (value) {
11474                            var user = vm.form.createUser(vm.form.userTypes.user_participant);
11475
11476                            vm.form.updateUser(user.uniqId, value);
11477                        });
11478
11479                        usersWatch();
11480                    }
11481                });
11482
11483                vm.progress = false;
11484            }
11485        },
11486        sendReport: function () {
11487            vm.form.submitted = true;
11488            vm.form.accepted = false;
11489
11490            vm.save();
11491        },
11492        sendAccepted: function () {
11493            vm.form.submitted = true;
11494            vm.form.accepted = true;
11495
11496            vm.save();
11497        },
11498        setUsers: function (users) {
11499
11500        },
11501        save: function () {
11502            if (vm.progress || $scope.projectReportForm.$invalid) {
11503                return;
11504            }
11505
11506            vm.form.documents_files = vm.documents_files;
11507
11508            vm.form.event = vm.requestController.getEventData();
11509
11510            vm.form.save()
11511                .then(function (response) {
11512                    $window.location.href = Routing.generate('event_view', {id: response.data.id});
11513                }, function (response) {
11514
11515                });
11516        }
11517    };
11518
11519    vm.fields.$fields.users.uiSelectOptions.onSelect = function (item, model, options) {
11520        vm.form.updateUser(options.index, item);
11521    };
11522
11523    return vm;
11524}]);
11525
11526},{}],107:[function(require,module,exports){
11527'use strict';
11528
11529angular.module('far.project').controller('ProjectRequestController', ["$rootScope", "$window", "$log", "eventProjectRequestForm", "maps", "Geocoder", "Project", "$scope", "partners", "FileUploader", function ($rootScope, $window, $log, eventProjectRequestForm, maps, Geocoder, Project, $scope, partners, FileUploader) {
11530    var geocoder = new Geocoder();
11531
11532    var vm = {
11533        progress: true,
11534        submitted: false,
11535        users: [],
11536        form: {},
11537        fields: eventProjectRequestForm,
11538        eventType: null,
11539        eventUserTypes: {},
11540        init: function () {
11541            if (arguments.length > 0) {
11542                vm.form = Project.get(arguments[0], vm.eventUserTypes, function () {
11543                    vm.form.disciplines = vm.form.disciplines[0]
11544                    vm.form.event_project.main_banner=vm.form.main_banner;
11545                    var partnersWatch = $rootScope.$watch(function () {
11546                        return partners.list.length;
11547                    }, function (length) {
11548                        if (length > 0) {
11549                            var projectPartnersLength = vm.form.partners.length;
11550
11551                            if (projectPartnersLength) {
11552                                partners.list.forEach(function (partner) {
11553                                    if (length == projectPartnersLength) {
11554                                        partner.selected = true;
11555                                    } else {
11556                                        vm.form.partners.forEach(function (selectedPartner) {
11557                                            if (partner.id == selectedPartner.id) {
11558                                                partner.selected = true;
11559                                            }
11560                                        });
11561                                    }
11562                                });
11563                            }
11564
11565                            partnersWatch();
11566                        }
11567                    });
11568
11569                    if (vm.form.coordinates) {
11570                        vm.map.center = vm.form.coordinates;
11571                        vm.map.markers = [angular.merge({id: 1}, vm.form.coordinates)];
11572                    }
11573
11574                    if (vm.form.background_image) {
11575                        if (Object.keys(vm.form.background_image).length) {
11576                            var backgroundImage = new FileUploader.FileItem(vm.fields.$fields.backgroundImage.uploader, {
11577                                lastModifiedDate: new Date(),
11578                                size: 1e6,
11579                                name: vm.form.background_image.image_name
11580                            });
11581
11582                            backgroundImage.progress = 100;
11583                            backgroundImage.isUploaded = true;
11584                            backgroundImage.isSuccess = true;
11585                            backgroundImage.serverData = angular.merge({}, vm.form.background_image);
11586
11587                            vm.fields.$fields.backgroundImage.uploader.queue.push(backgroundImage);
11588                        }
11589                    }
11590
11591                    vm.form.event_project.documents_files.forEach(function (serverFile) {
11592                        var newFile = new FileUploader.FileItem(vm.fields.$fields.documentsFiles.uploader, {
11593                            lastModifiedDate: new Date(),
11594                            size: 1e6,
11595                            name: serverFile.original_name
11596                        });
11597
11598                        newFile.progress = 100;
11599                        newFile.isUploaded = true;
11600                        newFile.isSuccess = true;
11601                        newFile.serverData = angular.merge({}, serverFile);
11602
11603                        vm.fields.$fields.documentsFiles.uploader.queue.push(newFile);
11604                    });
11605
11606                    vm.form.event_project.users.forEach(function (user) {
11607                        if (user.event_project_user_type.system_name == 'user_participant') {
11608                            vm.users.push(user.user);
11609                        }
11610                    });
11611
11612                    vm.progress = false;
11613                });
11614            } else {
11615                vm.form = Project.new({
11616                    event_project: {
11617                        documents: {},
11618                        users: [],
11619                        participants: {
11620                            min: 1,
11621                            max: 500
11622                        }
11623                    },
11624                    type: vm.eventType,
11625                    partners: []
11626                }, vm.eventUserTypes);
11627
11628                vm.progress = false;
11629            }
11630        },
11631        submit: function () {
11632            if (vm.submitted || $scope.eventProjectRequestForm.$invalid) {
11633                return;
11634            }
11635
11636            vm.submitted = true;
11637            vm.progress = true;
11638
11639            if (vm.form.event_project.accepted == undefined) {
11640                vm.form.event_project.accepted = vm.fields.$fields.accepted.items[0];
11641            }
11642            vm.form.main_banner=vm.form.event_project.main_banner;
11643
11644            if (vm.map.markers.length > 0) {
11645                vm.form.latitude = vm.map.markers[0].latitude;
11646                vm.form.longitude = vm.map.markers[0].longitude;
11647            }
11648
11649            vm.form.event_project.documents_files = vm.documents_files;
11650
11651            vm.form.save()
11652                .then(function (response) {
11653                    $window.location.href = Routing.generate('event_view', {id: response.data.id});
11654                }, function (response) {
11655                    $log.error(response);
11656
11657                    vm.submitted = false;
11658                    vm.progress = false;
11659                });
11660        },
11661        accepted: function () {
11662            vm.form.event_project.accepted = vm.fields.$fields.accepted.items[1];
11663
11664            vm.submit();
11665        },
11666        reject: function () {
11667            vm.form.event_project.accepted = vm.fields.$fields.accepted.items[2];
11668
11669            vm.submit();
11670        },
11671        map: {
11672            center: maps.getDefaultCenter(),
11673            zoom: maps.getDefaultZoom(),
11674            markers: [],
11675            events: {
11676                click: function (map, eventName, event) {
11677                    var marker = geocoder.getLatLngObject(event[0].latLng);
11678                    marker.id = 1;
11679                    vm.map.markers = [marker];
11680                }
11681            }
11682        },
11683        getEventData: function () {
11684            return {
11685                brief: vm.form.brief,
11686                description: vm.form.description
11687            };
11688        },
11689        changeDocument: function ($index, document) {
11690            if (!vm.form.event_project.documents[$index]) {
11691                vm.form.event_project.documents[$index] = document;
11692            } else {
11693                delete vm.form.event_project.documents[$index];
11694            }
11695        }
11696    };
11697
11698    vm.fields.$fields.user_director.uiSelectOptions.onSelect = function (item, model, options) {
11699        vm.form.event_project.updateUser(options.index, item);
11700    };
11701
11702    vm.fields.$fields.user_main_judge.uiSelectOptions.onSelect = function (item, model, options) {
11703        vm.form.event_project.updateUser(options.index, item);
11704    };
11705
11706    vm.fields.$fields.club.uiSelectOptions.onSelect = function (item) {
11707        vm.form.event_project.club = item ? item : null;
11708    };
11709
11710    vm.fields.$fields.camp.uiSelectOptions.onSelect = function (item) {
11711        vm.form.camp = item ? item : null;
11712    };
11713
11714    vm.fields.$fields.location.options.ngBlur = function changeLocation() {
11715        if (vm.form.location) {
11716            geocoder.getLocationsByAddress(vm.form.location).then(function (response) {
11717                var marker = {id: 1};
11718
11719                if (response.result.length > 0) {
11720                    vm.map.center = geocoder.getLatLngObject(response.result[0].geometry.location);
11721                    angular.merge(marker, geocoder.getLatLngObject(response.result[0].geometry.location));
11722                    vm.map.markers = [marker];
11723                }
11724            })
11725        }
11726    };
11727
11728    return vm;
11729}]);
11730
11731},{}],108:[function(require,module,exports){
11732require('./project.module.js');
11733require('./controllers/report.controller');
11734require('./controllers/request.controller');
11735
11736},{"./controllers/report.controller":106,"./controllers/request.controller":107,"./project.module.js":109}],109:[function(require,module,exports){
11737'use strict';
11738
11739require('../core/core');
11740require('../../modules/forms/forms');
11741require('../../modules/maps/maps');
11742
11743require('../../models/project/project');
11744require('../../models/project/projectReport');
11745require('../../models/project/projectUserType');
11746
11747require('../../forms/projectReportForm');
11748require('../../forms/eventProjectRequestForm');
11749
11750require('../../helpers/show-modal-message/show-modal-message');
11751require('../../helpers/users/users.module');
11752
11753require('../fos_user/directives/unique-user');
11754
11755require('../../modals/mountain-route-form/mountain-route-form');
11756require('../../modals/slider/slider');
11757
11758require('../documents/documents.module');
11759
11760angular.module('far.project', [
11761    'ngTouch',
11762    'dndLists',
11763    'ngMessages',
11764    'angularFileUpload',
11765    'ui.select',
11766    'ui.bootstrap',
11767    'dekky.forms',
11768    'far.models.project.project',
11769    'far.models.project.projectReport',
11770    'far.models.project.projectUserType',
11771    'far.core',
11772    'far.maps',
11773    'far.forms.projectReportForm',
11774    'far.forms.eventProjectRequestForm',
11775    'templates',
11776    'far.helpers.showModalMessage',
11777    'far.helpers.users',
11778    'far.fos_user.uniqueUser',
11779    'far.modals.slider',
11780    'far.documents.search'
11781]).value('formsConfig', {
11782    theme: '/dekky.forms/themes/far'
11783}).run(["$templateCache", function ($templateCache) {
11784    $templateCache.put('/far.project/fields/partnersCollection.html',
11785        '<div ng-init="model = model || []" ng-model="model">' +
11786        '<div repeat-collection ng-init="fieldIndex = $index" ng-form="childForm">' +
11787        '<div class="form-group right">' +
11788        '<button class="btn-gold" type="button" ng-click="field.doDelete(item, model, $index)">{{ field.buttons.remove }}</button>' +
11789        '</div>' +
11790        '<form-row ng-model="item.name" field="field.childForm.$fields.name" field-index="fieldIndex"></form-row>' +
11791        '<p class="form__error" role="alert" ng-if="childForm.$$parentForm.$submitted && childForm.name.$error.required">Обязательное поле</p>' +
11792        '<form-row ng-model="item.url" field="field.childForm.$fields.url" field-index="fieldIndex"></form-row>' +
11793        '<p class="form__error" role="alert" ng-if="childForm.$$parentForm.$submitted" ng-messages="childForm.url.$error">' +
11794        '<span ng-message="required">Обязательное поле</span>' +
11795        '<span ng-message="url">Урл в неверном формате</span>' +
11796        '</p>' +
11797        '<form-row ng-model="item.logo" field="field.childForm.$fields.logo" field-index="fieldIndex"></form-row>' +
11798        '<div class="form__line"></div>' +
11799        '</div>' +
11800
11801        '<div class="form-group">' +
11802        '<button class="btn-standart" type="button" ng-click="field.addItem(model)">{{ field.buttons.add }}</button>' +
11803        '</div>' +
11804        '</div>'
11805    );
11806}]);
11807
11808},{"../../forms/eventProjectRequestForm":148,"../../forms/projectReportForm":155,"../../helpers/show-modal-message/show-modal-message":167,"../../helpers/users/users.module":169,"../../modals/mountain-route-form/mountain-route-form":175,"../../modals/slider/slider":182,"../../models/project/project":223,"../../models/project/projectReport":224,"../../models/project/projectUserType":225,"../../modules/forms/forms":244,"../../modules/maps/maps":338,"../core/core":38,"../documents/documents.module":46,"../fos_user/directives/unique-user":66}],110:[function(require,module,exports){
11809'use strict';
11810
11811angular.module('far.rank')
11812    .controller('RankIndexController', ["$log", "$http", function ($log, $http) {
11813        var vm = {
11814            loaded: true,
11815            submitted: false,
11816            params: {
11817                limit: 50,
11818                offset: 0,
11819                category: null
11820            },
11821            total: {
11822                count: 0,
11823                pages: null
11824            },
11825            data: [],
11826            submit: function (next) {
11827                if (vm.submitted) {
11828                    return false;
11829                }
11830
11831                if (!next) {
11832                    vm.params.offset = 0;
11833                    vm.params.category = null;
11834
11835                    vm.total.count = 0;
11836                    vm.total.pages = null;
11837
11838                    vm.data = [];
11839                }
11840
11841                vm.submitted = true;
11842
11843                $http.get(Routing.generate('api_get_rank_list', vm.params)).then(function (response) {
11844                    vm.total.count = response.headers('X-Total-Count');
11845                    vm.total.pages = Math.ceil(vm.total.count / vm.params.limit);
11846
11847                    if (response.data) {
11848                        for (var i in response.data) {
11849                            var user = response.data[i];
11850
11851                            user['url'] = Routing.generate('user_view', {userId: user.id});
11852
11853                            vm.data.push(user);
11854                        }
11855                    }
11856
11857                    vm.submitted = false;
11858                    vm.loaded = false;
11859                }, function errorCallback(response) {
11860                    $log.error(response);
11861
11862                    vm.submitted = false;
11863                });
11864            },
11865            next: function () {
11866                vm.params.offset += vm.params.limit;
11867
11868                vm.submit(true);
11869            }
11870        };
11871
11872        vm.submit();
11873
11874        return vm;
11875    }]);
11876
11877},{}],111:[function(require,module,exports){
11878'use strict';
11879
11880angular.module('far.rank')
11881    .controller('RankYearController', ["$log", "$http", function ($log, $http) {
11882        var vm = {
11883            loaded: true,
11884            submitted: false,
11885            params: {
11886                limit: 50,
11887                offset: 0,
11888                category: null
11889            },
11890            total: {
11891                count: 0,
11892                pages: null
11893            },
11894            data: [],
11895            submit: function (next) {
11896                if (vm.submitted) {
11897                    return false;
11898                }
11899
11900                if (!next) {
11901                    vm.params.offset = 0;
11902                    vm.params.category = null;
11903
11904                    vm.total.count = 0;
11905                    vm.total.pages = null;
11906
11907                    vm.data = [];
11908                }
11909
11910                vm.submitted = true;
11911
11912                $http.get(Routing.generate('api_get_rank_year_list', vm.params)).then(function (response) {
11913                    vm.total.count = response.headers('X-Total-Count');
11914                    vm.total.pages = Math.ceil(vm.total.count / vm.params.limit);
11915
11916                    if (response.data) {
11917                        for (var i in response.data) {
11918                            var user = response.data[i];
11919
11920                            user['url'] = Routing.generate('user_view', {userId: user.id});
11921
11922                            vm.data.push(user);
11923                        }
11924                    }
11925
11926                    vm.submitted = false;
11927                    vm.loaded = false;
11928                }, function errorCallback(response) {
11929                    $log.error(response);
11930
11931                    vm.submitted = false;
11932                });
11933            },
11934            next: function () {
11935                vm.params.offset += vm.params.limit;
11936
11937                vm.submit(true);
11938            }
11939        };
11940
11941        vm.submit();
11942
11943        return vm;
11944    }]);
11945
11946},{}],112:[function(require,module,exports){
11947require('./rank.module');
11948require('./controllers/index.controller');
11949require('./controllers/year.controller');
11950
11951},{"./controllers/index.controller":110,"./controllers/year.controller":111,"./rank.module":113}],113:[function(require,module,exports){
11952'use strict';
11953
11954require('../core/core');
11955require('../../modules/pagination/pagination');
11956
11957require('../../helpers/show-modal-message/show-modal-message');
11958
11959angular.module('far.rank', [
11960	'ngTouch',
11961	'ui.bootstrap',
11962	'dekky.pagination',
11963	'far.core',
11964	'far.helpers.showModalMessage'
11965]).value('formsConfig', {
11966	theme: '/dekky.forms/themes/far'
11967});
11968
11969},{"../../helpers/show-modal-message/show-modal-message":167,"../../modules/pagination/pagination":341,"../core/core":38}],114:[function(require,module,exports){
11970/**
11971 * Created by phatbass on 2/9/16.
11972 */
11973
11974angular.module('far.search')
11975    .controller('SearchAlpClubController', ["$log", "$http", "form", "formsUtils", "autocomplete", function ($log, $http, form, formsUtils, autocomplete) {
11976        var vm = {
11977            loaded: true,
11978            submitted: false,
11979            includeAll: false,
11980            form: {},
11981            current: {
11982                offset: 0,
11983                limit: 30,
11984                count: '',
11985                data: []
11986            },
11987            total: {
11988                count: 0,
11989                pages: null
11990            },
11991            formSearchClub: form('formSearchClub'),
11992            submit: function ( next ) {
11993                if (vm.submitted) {
11994                    return false;
11995                }
11996
11997                if ( !next ) {
11998                    vm.current.offset = 0;
11999                    vm.current.data = [];
12000                    vm.total.count = 0;
12001                    vm.total.pages = null;
12002                }
12003
12004                var data = angular.merge({}, vm.form);
12005                if(1 > Object.keys(data).length){
12006                    if('' !== window.location.hash){
12007                        data = JSON.parse(decodeURIComponent(atob(window.location.hash.substring(1))));
12008                    }
12009                }
12010                this.data = data;
12011                window.location.hash = btoa(encodeURIComponent(JSON.stringify(data)));
12012
12013                if ( angular.isObject( data.member ) ) {
12014                    data.member = data.member.id;
12015                }
12016
12017                if ( angular.isObject( data.qualification ) ) {
12018                    data.qualification = data.qualification.id;
12019                }
12020
12021                if ( angular.isObject( data.achievements ) ) {
12022                    data.achievements = data.achievements.id;
12023                }
12024
12025                data['offset'] = vm.current.offset;
12026                data['limit'] = vm.current.limit;
12027
12028                data['subclub'] = true;
12029                vm.submitted = true;
12030
12031                if (data.city && data.city.name) {
12032                    data.city = data.city.name;
12033                }
12034
12035                if (data.region && data.city.region) {
12036                    data.region = data.region.name;
12037                }
12038
12039                $http.get(Routing.generate('api_club_search', data)).then(function (response) {
12040                    vm.total.count = response.headers('X-Total-Count');
12041                    vm.total.pages = Math.ceil( vm.total.count / vm.current.limit );
12042
12043                    for ( var id in response.data ) {
12044                        response.data[ id ]['url'] = Routing.generate('club_members', {id: response.data[id].id});
12045
12046                        if ( response.data[ id ].users.length ) {
12047                            response.data[ id ].users = response.data[ id ].users.map(function(user) {
12048                                user['url'] = Routing.generate('user_view', {userId: user.id});
12049
12050                                return user;
12051                            });
12052                        }
12053
12054                        vm.current.data.push( response.data[ id ] );
12055                    }
12056
12057                    vm.current.count = 'Альпинистские клубы России';
12058
12059                    vm.submitted = false;
12060                }, function errorCallback(response) {
12061                    $log.error(response);
12062
12063                    vm.submitted = false;
12064                });
12065            },
12066
12067            next: function () {
12068                vm.current.offset += vm.current.limit;
12069                vm.submit( true );
12070            },
12071
12072            getTotalCount: function () {
12073                return vm.current.count;
12074            }
12075        };
12076
12077        vm.formSearchClub
12078            .addField('region', 'uiSelect', {
12079                validators: {
12080                    required: false
12081                },
12082                options: {
12083                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
12084                    class: 'form__ui-select width-400 margin_r_20'
12085                },
12086                uiSelectOptions: {
12087                    matchTitle: '{{ $select.selected.name }} ',
12088                    choicesTitle: '{{ item.name }}',
12089                    match: {
12090                        placeholder: 'Регион',
12091                        allowClear: true
12092                    },
12093                    choices: {
12094                        repeat: 'item in field.items track by $index',
12095                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "KladrRegion", "region")',
12096                        refreshDelay: 400
12097                    },
12098                    refreshAutoComplete: autocomplete.refreshAutoComplete,
12099                    onSelect: function (item) {
12100                        if (item) {
12101                            vm.form.region = item;
12102                        }
12103                    }
12104                },
12105                fieldData: {
12106                    name: 'region'
12107                }
12108            }, autocomplete.get('region'))
12109            .addField('city', 'uiSelect', {
12110                validators: {
12111                    required: false
12112                },
12113                options: {
12114                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
12115                    class: 'form__ui-select width-400 margin_r_20'
12116                },
12117                uiSelectOptions: {
12118                    matchTitle: '{{ $select.selected.name }} ',
12119                    choicesTitle: '{{ item.name }}',
12120                    match: {
12121                        placeholder: 'Город',
12122                        allowClear: true
12123                    },
12124                    choices: {
12125                        repeat: 'item in field.items track by $index',
12126                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "KladrCity", "city")',
12127                        refreshDelay: 400
12128                    },
12129                    refreshAutoComplete: function(name, term, object) {
12130                        var params = {};
12131                        if (vm.form.region && vm.form.region.id) {
12132                            params.region = vm.form.region.id;
12133                        }
12134                        return autocomplete.refreshAutoComplete(name, term, object, params)
12135                    },
12136                    onSelect: function (item) {
12137                        if (item) {
12138                            vm.form.city = item;
12139                        }
12140                    }
12141                },
12142                fieldData: {
12143                    name: 'city'
12144                }
12145            }, autocomplete.get('city'))
12146        ;
12147
12148        vm.submit();
12149
12150        return vm;
12151    }]);
12152
12153},{}],115:[function(require,module,exports){
12154/**
12155 * Created by phatbass on 2/9/16.
12156 */
12157
12158angular.module('far.search')
12159    .controller('SearchCampController', ["$log", "$http", "form", "formsUtils", "campCountry", "campRegion", "autocomplete", function ($log, $http, form, formsUtils, campCountry, campRegion, autocomplete) {
12160        var vm = {
12161            loaded: true,
12162            submitted: false,
12163            form: {},
12164            current: {
12165                offset: 0,
12166                limit: 100,
12167                count: '',
12168                data: []
12169            },
12170            autoCompleteSelect: {
12171                country: null,
12172                region: null,
12173                city: null
12174            },
12175            total: {
12176                count: 0,
12177                pages: null
12178            },
12179            formSearchCamp: form('formSearchCamp'),
12180            submit: function ( next ) {
12181                if (vm.submitted) {
12182                    return false;
12183                }
12184
12185                if ( !next ) {
12186                    vm.current.offset = 0;
12187                    vm.current.data = [];
12188                    vm.total.count = 0;
12189                    vm.total.pages = null;
12190                }
12191
12192                var data = angular.merge({}, vm.form);
12193                if(1 > Object.keys(data).length){
12194                    if('' !== window.location.hash){
12195                        data = JSON.parse(decodeURIComponent(atob(window.location.hash.substring(1))));
12196                    }
12197                }
12198                this.data = data;
12199                window.location.hash = btoa(encodeURIComponent(JSON.stringify(data)));
12200
12201
12202
12203                data['offset'] = vm.current.offset;
12204                data['limit'] = vm.current.limit;
12205
12206                if ( angular.isObject( data.country ) ) {
12207                    data.country = data.country.id
12208                }
12209
12210                vm.submitted = true;
12211
12212                $http.get(Routing.generate('api_camp_search', data)).then(function (response) {
12213                    vm.total.count = response.headers('X-Total-Count');
12214                    vm.total.pages = Math.ceil( vm.total.count / vm.current.limit );
12215
12216                    for ( var id in response.data ) {
12217                        response.data[ id ]['url'] = Routing.generate('camp_general', {id: response.data[id].id});
12218
12219                        vm.current.data.push( response.data[ id ] );
12220                    }
12221
12222                    vm.current.count = formsUtils.numEnding( vm.total.count, ['Найден', 'Найдено', 'Найдено'] ) + ' ' + vm.total.count + ' ' + formsUtils.numEnding( vm.total.count, ['клуб', 'клуба', 'клубов'] );
12223
12224                    vm.submitted = false;
12225                }, function errorCallback(response) {
12226                    $log.error(response);
12227
12228                    vm.submitted = false;
12229                });
12230            },
12231            next: function () {
12232                vm.current.offset += vm.current.limit;
12233
12234                vm.submit( true );
12235            },
12236            getTotalCount: function () {
12237                return vm.current.count;
12238            }
12239        };
12240
12241        vm.formSearchCamp
12242            .addField('country', 'uiSelect', {
12243                validators: {
12244                    required: false
12245                },
12246                options: {
12247                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
12248                    class: 'form__ui-select width-650'
12249                },
12250                uiSelectOptions: {
12251                    matchTitle: '{{ $select.selected.name }} ',
12252                    choicesTitle: '{{ item.name }}',
12253                    match: {
12254                        placeholder: 'Страна',
12255                        allowClear: true
12256                    },
12257                    choices: {
12258                        repeat: 'item in field.items track by item.id',
12259                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "CampCountry", "campCountry")',
12260                        refreshDelay: 0
12261                    },
12262                    refreshAutoComplete: autocomplete.refreshAutoComplete,
12263                    onSelect: function (item) {
12264                        if (item) {
12265                            vm.autoCompleteSelect.country = item.id;
12266                            vm.autoCompleteSelect.region = null;
12267
12268                            vm.formSearchCamp.$fields.region.items = [];
12269
12270                            vm.form.country = item;
12271                        }
12272                    }
12273                }
12274            }, autocomplete.get('campCountry'))
12275            .addField('region', 'uiSelect', {
12276                validators: {
12277                    required: false
12278                },
12279                options: {
12280                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
12281                    class: 'form__ui-select width-650'
12282                },
12283                uiSelectOptions: {
12284                    matchTitle: '{{ $select.selected.name }} ',
12285                    choicesTitle: '{{ item.name }}',
12286                    match: {
12287                        placeholder: 'Регион',
12288                        allowClear: true
12289                    },
12290                    choices: {
12291                        repeat: 'item in field.items track by item.id',
12292                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "KladrRegion", "region")',
12293                        refreshDelay: 400
12294                    },
12295                    refreshAutoComplete: autocomplete.refreshAutoComplete,
12296                    onSelect: function (item) {
12297                        if (item) {
12298                            vm.form.region = item.name;
12299                        }
12300                    }
12301                },
12302                fieldData: {
12303                    name: 'region'
12304                }
12305            }, autocomplete.get('region'));
12306
12307        vm.submit();
12308        return vm;
12309    }]);
12310
12311},{}],116:[function(require,module,exports){
12312/**
12313 * Created by phatbass on 2/9/16.
12314 */
12315
12316angular.module('far.search')
12317    .controller('SearchClimberController', ["$timeout", "$log", "$http", "$scope", "form", "autocomplete", "userQualification", "userAchievements", "formsUtils", function ($timeout, $log, $http, $scope, form, autocomplete, userQualification, userAchievements, formsUtils) {
12318        var vm = {
12319            loaded: true,
12320            submitted: false,
12321            filterShow: true,
12322            form: {},
12323            userClimber: {
12324                offset: 0,
12325                limit: 100,
12326                data: []
12327            },
12328            total: {
12329                count: 0,
12330                pages: null
12331            },
12332            fistload: true,
12333            formSearchClimber: form('formSearchClimber'),
12334            clearFilters: clearFilters,
12335            submit: function ( next ) {
12336                if (vm.submitted) {
12337                    return false;
12338                }
12339
12340                if ( !next ) {
12341                    vm.userClimber.offset = 0;
12342                    vm.userClimber.data = [];
12343                    vm.total.count = 0;
12344                    vm.total.pages = null;
12345                }
12346
12347                var data = angular.merge({}, vm.form);
12348                if(1 > Object.keys(data).length){
12349                    if('' !== window.location.hash){
12350                        data = JSON.parse(decodeURIComponent(atob(window.location.hash.substring(1))));
12351                    }
12352                }
12353                this.data = data;
12354                window.location.hash = btoa(encodeURIComponent(JSON.stringify(data)));
12355
12356                if ( angular.isObject( data.member ) ) {
12357                    data.member = data.member.id;
12358                }
12359
12360                if ( angular.isObject( data.qualification ) ) {
12361                    data.qualification = data.qualification.id;
12362                }
12363
12364                if ( angular.isObject( data.achievements ) ) {
12365                    data.achievements = data.achievements.id;
12366                }
12367
12368                data['offset'] = vm.userClimber.offset;
12369                data['limit'] = vm.userClimber.limit;
12370
12371                vm.submitted = true;
12372
12373                $http.get(Routing.generate('api_climber_search', data)).then(function (response) {
12374                    vm.total.count = response.headers('X-Total-Count');
12375                    vm.total.pages = Math.ceil( vm.total.count / vm.userClimber.limit );
12376
12377                    for ( var id in response.data ) {
12378                        response.data[ id ]['url'] = Routing.generate('user_view', {userId: response.data[ id].id});
12379                        vm.userClimber.data.push( response.data[ id ] );
12380                    }
12381
12382                    vm.submitted = false;
12383                    vm.fistload = false;
12384                }, function errorCallback(response) {
12385                    $log.error(response);
12386
12387                    vm.submitted = false;
12388                });
12389            },
12390            next: function () {
12391                vm.userClimber.offset += vm.userClimber.limit;
12392
12393                vm.submit( true );
12394            },
12395            getTotalCount: function () {
12396                if (!vm.fistload) {
12397                    return formsUtils.numEnding( vm.total.count, ['Найден', 'Найдено', 'Найдено'] ) + ' ' + vm.total.count + ' ' + formsUtils.numEnding( vm.total.count, ['человек', 'человека', 'человек'] );
12398                }
12399
12400                return '';
12401            }
12402        };
12403
12404        if('' !== window.location.hash){
12405            vm.submit();
12406        }
12407
12408        vm.formSearchClimber
12409            .addField('died', 'checkbox', {
12410                label: 'Память',
12411                options: {
12412                    ngChange: function () {
12413                        $timeout(function() {
12414                            vm.submit();
12415                        });
12416                    }
12417                }
12418            })
12419            .addField('achievements', 'selectObject', {
12420                validators: {
12421                    required: false
12422                },
12423                options: {
12424                    defaultOption: 'Квалификация и достижения',
12425                    class: 'form__item form__item_select width-200 margin_r_20',
12426                    ngChange: function () {
12427                        $timeout(function() {
12428                            vm.submit();
12429                        });
12430                    }
12431                },
12432                ngOptions: 'item as item.name for item in field.items track by item.id',
12433                label: null
12434            }, userAchievements.list)
12435            .addField('user_region', 'uiSelect', {
12436                validators: {
12437                    required: false
12438                },
12439                options: {
12440                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
12441                    class: 'form__ui-select width-170 margin_r_20',
12442                    uiSelectManualClear: 'clearCitySelectEvent'
12443                },
12444                uiSelectOptions: {
12445                    matchTitle: '{{ $select.selected.name }} ',
12446                    choicesTitle: '{{ item.name }}',
12447                    match: {
12448                        placeholder: 'Регион',
12449                        allowClear: true
12450                    },
12451                    choices: {
12452                        repeat: 'item in field.items track by item.id',
12453                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "UserCity", "user_region")',
12454                        refreshDelay: 0
12455                    },
12456                    refreshAutoComplete: autocomplete.refreshAutoComplete,
12457                    onSelect: function (item) {
12458                        vm.form.region = item ? item.name : null;
12459
12460                        vm.submit();
12461                    }
12462                }
12463            }, autocomplete.get('user_region'))
12464            .addField('user_city', 'uiSelect', {
12465                validators: {
12466                    required: false
12467                },
12468                options: {
12469                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
12470                    class: 'form__ui-select width-170 margin_r_20',
12471                    uiSelectManualClear: 'clearCitySelectEvent'
12472                },
12473                uiSelectOptions: {
12474                    matchTitle: '{{ $select.selected.name }} ',
12475                    choicesTitle: '{{ item.name }}',
12476                    match: {
12477                        placeholder: 'Город',
12478                        allowClear: true
12479                    },
12480                    choices: {
12481                        repeat: 'item in field.items track by item.id',
12482                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "UserCity", "user_city")',
12483                        refreshDelay: 0
12484                    },
12485                    refreshAutoComplete: autocomplete.refreshAutoComplete,
12486                    onSelect: function (item) {
12487                        vm.form.city = item ? item.name : null;
12488
12489                        vm.submit();
12490                    }
12491                }
12492            }, autocomplete.get('user_city'))
12493            .addField('qualification', 'selectObject', {
12494                validators: {
12495                    required: false
12496                },
12497                options: {
12498                    defaultOption: 'Разряд',
12499                    class: 'form__item form__item_select width-140 margin_r_20',
12500                    ngChange: function () {
12501                        $timeout(function() {
12502                            vm.submit();
12503                        });
12504                    }
12505                },
12506                ngOptions: 'item as item.name for item in field.items track by item.id',
12507                label: null
12508            }, userQualification.list)
12509            .addField('club', 'uiSelect', {
12510                validators: {
12511                    required: false
12512                },
12513                options: {
12514                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
12515                    class: 'form__ui-select width-170 margin_r_20',
12516                    uiSelectManualClear: 'clearClubSelectEvent'
12517                },
12518                uiSelectOptions: {
12519                    matchTitle: '{{ $select.selected.name }} ',
12520                    choicesTitle: '{{ item.name }}',
12521                    match: {
12522                        placeholder: 'Федерация/Клуб',
12523                        allowClear: true
12524                    },
12525                    choices: {
12526                        repeat: 'item in field.items track by item.id',
12527                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Club", "club")',
12528                        refreshDelay: 0
12529                    },
12530                    refreshAutoComplete: autocomplete.refreshAutoComplete,
12531                    onSelect: function (item) {
12532                        vm.form.club = item ? item.id : null;
12533
12534                        vm.submit();
12535                    }
12536                }
12537            }, autocomplete.get('club'))
12538            .addField('member', 'selectObject', {
12539                validators: {
12540                    required: false
12541                },
12542                options: {
12543                    defaultOption: 'Членство ФАР',
12544                    class: 'form__item form__item_select width-170',
12545                    ngChange: function () {
12546                        $timeout(function() {
12547                            vm.submit();
12548                        });
12549                    }
12550                },
12551                ngOptions: 'item as item.name for item in field.items track by item.id',
12552                label: null
12553            }, [{
12554                    id: 1,
12555                    name: 'Да'
12556                }, {
12557                    id: 0,
12558                    name: 'Нет'
12559                }]);
12560
12561        function clearFilters() {
12562            $scope.$emit('clearClubSelectEvent');
12563            $scope.$emit('clearCitySelectEvent');
12564        }
12565        window.vm = vm;
12566        return vm;
12567    }]);
12568
12569},{}],117:[function(require,module,exports){
12570/**
12571 * Created by phatbass on 2/9/16.
12572 */
12573
12574angular.module('far.search')
12575    .controller('SearchClubController', ["$log", "$http", "form", "formsUtils", function ($log, $http, form, formsUtils) {
12576        var vm = {
12577            loaded: true,
12578            submitted: false,
12579            form: {},
12580            current: {
12581                offset: 0,
12582                limit: 30,
12583                count: '',
12584                data: []
12585            },
12586            total: {
12587                count: 0,
12588                pages: null
12589            },
12590            formSearchClub: form('formSearchClub'),
12591            submit: function ( next ) {
12592                if (vm.submitted) {
12593                    return false;
12594                }
12595
12596                if ( !next ) {
12597                    vm.current.offset = 0;
12598                    vm.current.data = [];
12599                    vm.total.count = 0;
12600                    vm.total.pages = null;
12601                }
12602
12603                var data = angular.merge({}, vm.form);
12604                if(1 > Object.keys(data).length){
12605                    if('' !== window.location.hash){
12606                        data = JSON.parse(decodeURIComponent(atob(window.location.hash.substring(1))));
12607                    }
12608                }
12609                this.data = data;
12610                window.location.hash = btoa(encodeURIComponent(JSON.stringify(data)));
12611
12612                if ( angular.isObject( data.member ) ) {
12613                    data.member = data.member.id;
12614                }
12615
12616                if ( angular.isObject( data.qualification ) ) {
12617                    data.qualification = data.qualification.id;
12618                }
12619
12620                if ( angular.isObject( data.achievements ) ) {
12621                    data.achievements = data.achievements.id;
12622                }
12623
12624                data['offset'] = vm.current.offset;
12625                data['limit'] = vm.current.limit;
12626                data['subclub'] = false;
12627
12628                vm.submitted = true;
12629
12630                $http.get(Routing.generate('api_club_search', data)).then(function (response) {
12631                    vm.total.count = response.headers('X-Total-Count');
12632                    vm.total.pages = Math.ceil( vm.total.count / vm.current.limit );
12633
12634                    for ( var id in response.data ) {
12635                        response.data[ id ]['url'] = Routing.generate('club_members', {id: response.data[id].id});
12636
12637                        if ( response.data[ id ].users.length ) {
12638                            response.data[ id ].users = response.data[ id ].users.map(function(user) {
12639                                user['url'] = Routing.generate('user_view', {userId: user.id});
12640
12641                                return user;
12642                            });
12643                        }
12644
12645                        vm.current.data.push( response.data[ id ] );
12646                    }
12647
12648                    vm.current.count = 'Региональные федерации альпинизма';
12649
12650                    vm.submitted = false;
12651                }, function errorCallback(response) {
12652                    $log.error(response);
12653
12654                    vm.submitted = false;
12655                });
12656            },
12657            next: function () {
12658                vm.current.offset += vm.current.limit;
12659
12660                vm.submit( true );
12661            },
12662            getTotalCount: function () {
12663                return vm.current.count;
12664            }
12665        };
12666
12667
12668
12669        vm.submit();
12670
12671        return vm;
12672    }]);
12673
12674},{}],118:[function(require,module,exports){
12675/**
12676 * Created by phatbass on 2/9/16.
12677 */
12678
12679angular.module('far.search')
12680    .controller('SearchInstructorController', ["$timeout", "$log", "$http", "$scope", "form", "autocomplete", "userQualification", "userAchievements", "formsUtils", function ($timeout, $log, $http, $scope, form, autocomplete, userQualification, userAchievements, formsUtils) {
12681        var vm = {
12682            loaded: true,
12683            searchString: '',
12684            showRequestForm: false,
12685            showError: false,
12686            errorMessage: '',
12687            requestData: {
12688                instructor: null,
12689                message: null,
12690                fio: null,
12691                email: null,
12692                phone: null
12693            },
12694            searchForm: form('searchForm'),
12695            jobSeekersOnly: false,
12696            requestForm: form('requestForm'),
12697            responseOk: true,
12698            responseMessage: '',
12699            isLoading: false,
12700            instructors: {
12701                offset: 0,
12702                limit: 100,
12703                data: []
12704            },
12705            total: {
12706                count: 0,
12707                pages: null
12708            },
12709            firstload: true,
12710            isMember: false,
12711            formatDate: function(d) {
12712                var add0 = function(n) {
12713                    return n > 9 ? n : '0' + n;
12714                }
12715                return add0(d.getDate()) + '.' + add0(d.getMonth()+1) + '.' + d.getFullYear();
12716            },
12717            instructorPeriod: function(instructor) {
12718                if (instructor.instructor_period_start && instructor.instructor_period_end) {
12719                    return 'Готов работать в период с '
12720                        + this.formatDate(new Date(instructor.instructor_period_start))
12721                        + ' по '
12722                        + this.formatDate(new Date(instructor.instructor_period_end));
12723                } else {
12724                    return 'Готов работать';
12725                }
12726            },
12727            init: function(climberData) {
12728                vm.requestData.fio = climberData.fio;
12729                vm.requestData.email = climberData.email;
12730                vm.requestData.phone = climberData.phone;
12731                vm.isMember = climberData.isMember;
12732                vm.loadInstructors();
12733            },
12734            openRequestForm: function(instructorId) {
12735                if (vm.isMember) {
12736                    vm.requestData.instructor = instructorId;
12737                    vm.showRequestForm = true;
12738                    vm.responseMessage = '';
12739                    vm.requestData.message = '';
12740                } else {
12741                    vm.errorMessage = 'Отправка сообщений доступна только членам ФАР.';
12742                    vm.errorTitle   = 'Ошибка';
12743                    vm.showError = true;
12744                }
12745                return false;
12746            },
12747            submitRequest: function() {
12748
12749                if (vm.isLoading) {
12750                    return false;
12751                }
12752
12753                vm.isLoading = true;
12754
12755                $http.post(Routing.generate('api_post_instructor_request'), vm.requestData).then(function (response) {
12756                    vm.responseMessage = 'Сообщение успешно отправлено.';
12757                    vm.responseOk = true;
12758                    vm.isLoading = false;
12759                }, function errorCallback(response) {
12760                    $log.error(response);
12761                    vm.responseMessage = 'Ошибка отправки сообщения.';
12762                    vm.responseOk = false;
12763                });
12764            },
12765            loadInstructors: function ( next ) {
12766                if (vm.isLoading) {
12767                    return false;
12768                }
12769
12770                if ( !next ) {
12771                    vm.instructors.offset = 0;
12772                    vm.instructors.data = [];
12773                    vm.total.count = 0;
12774                    vm.total.pages = null;
12775                }
12776
12777                var data = {
12778                    searchString: vm.searchString,
12779                    jobSeekersOnly: vm.jobSeekersOnly
12780                };
12781                //this.data = data;
12782
12783                data['offset'] = vm.instructors.offset;
12784                data['limit'] = vm.instructors.limit;
12785
12786                vm.isLoading = true;
12787
12788                $http.get(Routing.generate('api_instructor_search', data)).then(function (response) {
12789                    vm.total.count = response.headers('X-Total-Count');
12790                    vm.total.pages = Math.ceil( vm.total.count / vm.instructors.limit );
12791
12792                    for ( var id in response.data ) {
12793                        response.data[ id ]['url'] = Routing.generate('user_ascents_view', {userId: response.data[ id].id});
12794                        vm.instructors.data.push( response.data[ id ] );
12795                    }
12796
12797                    vm.isLoading = false;
12798                    vm.firstload = false;
12799                }, function errorCallback(response) {
12800                    $log.error(response);
12801
12802                    vm.isLoading = false;
12803                });
12804            },
12805            next: function () {
12806                vm.instructors.offset += vm.instructors.limit;
12807                vm.loadInstructors( true );
12808            },
12809            getTotalCount: function () {
12810                if (!vm.firstload) {
12811                    return formsUtils.numEnding( vm.total.count, ['Найден', 'Найдено', 'Найдено'] ) + ' ' + vm.total.count + ' ' + formsUtils.numEnding( vm.total.count, ['человек', 'человека', 'человек'] );
12812                }
12813
12814                return '';
12815            }
12816        };
12817
12818        vm.searchForm.addField('jobSeekersOnly', 'checkbox', {
12819            label: 'Показать желающих работать инструктором',
12820            options: {
12821                ngChange: function () {
12822                    $timeout(function() {
12823                        vm.loadInstructors();
12824                    });
12825                }
12826            }
12827        });
12828
12829        vm.requestForm
12830            .addField('message', 'textarea', {
12831                validators: {
12832                    required: true
12833                },
12834                options: {
12835                    placeholder: 'Сообщение',
12836                    rows: 5,
12837                    class: 'form__item',
12838                }
12839            })
12840            .addField('fio', 'text', {
12841                validators: {
12842                    required: true
12843                },
12844                options: {
12845                    placeholder: 'Фамилия, имя, отчество',
12846                    class: 'form__item',
12847                }
12848            })
12849            .addField('email', 'text', {
12850                validators: {
12851                    required: true
12852                },
12853                options: {
12854                    placeholder: 'Email',
12855                    class: 'form__item',
12856                }
12857            })
12858            .addField('phone', 'text', {
12859                validators: {
12860                    required: false
12861                },
12862                options: {
12863                    placeholder: 'Телефон',
12864                    class: 'form__item',
12865                }
12866            });
12867
12868        return vm;
12869    }]);
12870
12871},{}],119:[function(require,module,exports){
12872(function () {
12873    controller.$inject = ["$scope", "Search"];
12874    require('../../resources/search');
12875    require('../search-results/search-results.directive');
12876    angular.module('far.search').directive('searchBlock', searchBlock);
12877
12878    function searchBlock() {
12879        return {
12880            restrict: 'A',
12881            controller: controller,
12882            scope: {
12883                initialQuery: '=',
12884                initialItems: '=',
12885                initialTotal: '=',
12886                showMore: '=',
12887                query: '=',
12888                showFilter: '=',
12889                search: '=',
12890                filterButtonText: '=',
12891                type: '=',
12892                items: '=',
12893                total: '='
12894            }
12895        }
12896    }
12897
12898    /**
12899     * @param $scope
12900     * @param {Search} Search
12901     */
12902    function controller($scope, Search) {
12903        $scope.query = $scope.initialQuery;
12904        $scope.items = $scope.initialItems;
12905        $scope.total = $scope.initialTotal;
12906        $scope.search = _.debounce(search, 200);
12907        $scope.filterButtonText = filterButtonText;
12908        $scope.showFilter = true;
12909        $scope.showMore = showMore;
12910
12911        function filterButtonText() {
12912            return $scope.showFilter ? 'Скрыть фильтр' : 'Показать фильтр';
12913        }
12914
12915        function search(event) {
12916            if (event) {
12917                event.preventDefault();
12918            }
12919
12920            updateItems();
12921        }
12922
12923        function updateItems() {
12924            Search.search({
12925                type: $scope.type,
12926                query: $scope.query
12927            }).$promise.then(function (searchResults) {
12928                $scope.items = searchResults.items;
12929                $scope.total = searchResults.total;
12930            });
12931        }
12932
12933        function showMore() {
12934            Search.search({
12935                type: $scope.type,
12936                query: $scope.query,
12937                from: $scope.items.length
12938            }).$promise.then(function (searchResults) {
12939                $scope.items = $scope.items.concat(searchResults.items);
12940                $scope.total = searchResults.total;
12941            });
12942        }
12943    }
12944})();
12945
12946},{"../../resources/search":130,"../search-results/search-results.directive":128}],120:[function(require,module,exports){
12947(function () {
12948    var templateUrl = require('./search-result-event.html');
12949    angular.module('far.search').directive('searchResultEvent', searchResultEvent);
12950
12951    function searchResultEvent() {
12952        return {
12953            templateUrl: templateUrl
12954        };
12955    }
12956})();
12957
12958},{"./search-result-event.html":121}],121:[function(require,module,exports){
12959var ngModule;
12960try {
12961  ngModule = angular.module('templates');
12962} catch (e) {
12963  ngModule = angular.module('templates', []);
12964}
12965
12966ngModule.run(['$templateCache', function ($templateCache) {
12967  $templateCache.put('/app/search/directives/search-result-event/search-result-event.html',
12968    '<div class="event-item">\n' +
12969    '    <div class="event-item-left-block" ng-if="item.background_image.thumb_path" style="background-image: url(\'{{ item.background_image.thumb_path }}\')">\n' +
12970    '    </div>\n' +
12971    '    <div class="event-item-right-block">\n' +
12972    '        <div class="event-item-date" ng-if="item.all_year_round">Круглогодично</div>\n' +
12973    '        <div class="event-item-date" ng-if="!item.all_year_round">{{ item.date_from | date:\'dd.MM.yyyy\' }} - {{ item.date_to | date:\'dd.MM.yyyy\' }}</div>\n' +
12974    '        <div class="event-item-name">\n' +
12975    '            <a href="{{ item.route_info }}" target="_blank" ng-bind-html="item.highlighted_title | rawHtml"></a>\n' +
12976    '        </div>\n' +
12977    '        <div class="event-item-content" ng-bind-html="item.highlighted_text | rawHtml"></div>\n' +
12978    '        <div class="event-item-location">\n' +
12979    '            Место проведения: {{ item.location }}\n' +
12980    '        </div>\n' +
12981    '    </div>\n' +
12982    '</div>\n' +
12983    '\n' +
12984    '');
12985}]);
12986
12987module.exports = "/app/search/directives/search-result-event/search-result-event.html";
12988},{}],122:[function(require,module,exports){
12989(function () {
12990    var templateUrl = require('./search-result-news.html');
12991
12992    angular.module('far.search').directive('searchResultNews', searchResultNews);
12993
12994    function searchResultNews() {
12995        return {
12996            templateUrl: templateUrl
12997        };
12998    }
12999})();
13000
13001},{"./search-result-news.html":123}],123:[function(require,module,exports){
13002var ngModule;
13003try {
13004  ngModule = angular.module('templates');
13005} catch (e) {
13006  ngModule = angular.module('templates', []);
13007}
13008
13009ngModule.run(['$templateCache', function ($templateCache) {
13010  $templateCache.put('/app/search/directives/search-result-news/search-result-news.html',
13011    '<div class="news-item">\n' +
13012    '    <div class="news-item-left-block" ng-show="item.avatar.thumb_path" style="background-image: url(\'{{ item.avatar.thumb_path }}\');">\n' +
13013    '    </div>\n' +
13014    '    <div class="news-item-right-block">\n' +
13015    '        <div class="news-item-date">{{ item.created }}</div>\n' +
13016    '        <div class="news-item-name">\n' +
13017    '            <a href="{{ item.route_info }}" target="_blank" ng-bind-html="item.highlighted_title | rawHtml"></a>\n' +
13018    '        </div>\n' +
13019    '        <div class="news-item-author">{{ item.user.full_name }}</div>\n' +
13020    '        <div class="news-item-content" ng-bind-html="item.highlighted_text | rawHtml"></div>\n' +
13021    '        <div class="news-item-categories">\n' +
13022    '            <span class="news-item-category" ng-repeat="category in item.categories">\n' +
13023    '                <a href="{{ category.route_info }}" class="news-item-category-link">\n' +
13024    '                    {{ category.name }}\n' +
13025    '                </a>\n' +
13026    '                {{ $last ? \'\': \', \'}}\n' +
13027    '            </span>\n' +
13028    '        </div>\n' +
13029    '    </div>\n' +
13030    '</div>\n' +
13031    '');
13032}]);
13033
13034module.exports = "/app/search/directives/search-result-news/search-result-news.html";
13035},{}],124:[function(require,module,exports){
13036(function () {
13037    var templateUrl = require('./search-result-page.html');
13038
13039    angular.module('far.search').directive('searchResultPage', searchResultPage);
13040
13041    function searchResultPage() {
13042        return {
13043            templateUrl: templateUrl
13044        };
13045    }
13046})();
13047
13048},{"./search-result-page.html":125}],125:[function(require,module,exports){
13049var ngModule;
13050try {
13051  ngModule = angular.module('templates');
13052} catch (e) {
13053  ngModule = angular.module('templates', []);
13054}
13055
13056ngModule.run(['$templateCache', function ($templateCache) {
13057  $templateCache.put('/app/search/directives/search-result-page/search-result-page.html',
13058    '<div class="search-page-item">\n' +
13059    '    <div class="search-page-item-right-block">\n' +
13060    '        <div class="search-page-item-date">{{ item.created }}</div>\n' +
13061    '        <div class="search-page-item-name">\n' +
13062    '            <a href="{{ item.route_info }}" ng-bind-html="item.highlighted_title | rawHtml"></a>\n' +
13063    '        </div>\n' +
13064    '        <div class="search-page-item-content" ng-bind-html="item.highlighted_text | rawHtml"></div>\n' +
13065    '    </div>\n' +
13066    '</div>\n' +
13067    '');
13068}]);
13069
13070module.exports = "/app/search/directives/search-result-page/search-result-page.html";
13071},{}],126:[function(require,module,exports){
13072(function () {
13073    var templateUrl = require('./search-result-post.html');
13074
13075    angular.module('far.search').directive('searchResultPost', searchResultPost);
13076
13077    function searchResultPost() {
13078        return {
13079            templateUrl: templateUrl
13080        };
13081    }
13082})();
13083
13084},{"./search-result-post.html":127}],127:[function(require,module,exports){
13085var ngModule;
13086try {
13087  ngModule = angular.module('templates');
13088} catch (e) {
13089  ngModule = angular.module('templates', []);
13090}
13091
13092ngModule.run(['$templateCache', function ($templateCache) {
13093  $templateCache.put('/app/search/directives/search-result-post/search-result-post.html',
13094    '<div class="search-post-item">\n' +
13095    '    <div class="search-post-item-left-block" ng-show="item.image.thumb_path" style="background-image: url(\'{{ item.image.thumb_path }}\');">\n' +
13096    '    </div>\n' +
13097    '    <div class="search-post-item-right-block">\n' +
13098    '        <div class="search-post-item-date">{{ item.created }}</div>\n' +
13099    '        <div class="search-post-item-name">\n' +
13100    '            <a href="{{ item.route_info }}" ng-bind-html="item.highlighted_text | rawHtml"></a>\n' +
13101    '        </div>\n' +
13102    '        <div class="search-post-item-description" ng-bind-html="item.highlighted_text | rawHtml"></div>\n' +
13103    '    </div>\n' +
13104    '</div>\n' +
13105    '');
13106}]);
13107
13108module.exports = "/app/search/directives/search-result-post/search-result-post.html";
13109},{}],128:[function(require,module,exports){
13110(function () {
13111    var templateUrl = require('./search-results.html');
13112    require('../search-result-news/search-result-news.directive');
13113    require('../search-result-event/search-result-event.directive');
13114    require('../search-result-page/search-result-page.directive');
13115    require('../search-result-post/search-result-post.directive');
13116
13117    angular.module('far.search').directive('searchResults', searchResults);
13118
13119    function searchResults() {
13120        controller.$inject = ["$scope"];
13121        return {
13122            restrict: 'A',
13123            // replace: true,
13124            templateUrl: templateUrl,
13125            scope: {
13126                items: '=',
13127                showMore: '=',
13128                total: '=',
13129                hasNextResult: '='
13130            },
13131            controller: controller
13132        };
13133
13134        function controller($scope) {
13135            $scope.hasNextResult = hasNextResult;
13136
13137            function hasNextResult() {
13138                console.log($scope);
13139                return $scope.total > $scope.items.length;
13140            }
13141        }
13142    }
13143})();
13144
13145},{"../search-result-event/search-result-event.directive":120,"../search-result-news/search-result-news.directive":122,"../search-result-page/search-result-page.directive":124,"../search-result-post/search-result-post.directive":126,"./search-results.html":129}],129:[function(require,module,exports){
13146var ngModule;
13147try {
13148  ngModule = angular.module('templates');
13149} catch (e) {
13150  ngModule = angular.module('templates', []);
13151}
13152
13153ngModule.run(['$templateCache', function ($templateCache) {
13154  $templateCache.put('/app/search/directives/search-results/search-results.html',
13155    '<div class="search-results">\n' +
13156    '    <div class="search-result-row" ng-repeat="item in items" ng-switch="item.elastica_type">\n' +
13157    '        <div class="search-result row" ng-switch-when="news" search-result-news></div>\n' +
13158    '        <div class="search-result row" ng-switch-when="event" search-result-event></div>\n' +
13159    '        <div class="search-result row" ng-switch-when="post" search-result-post></div>\n' +
13160    '        <div class="search-result row" ng-switch-when="page" search-result-page></div>\n' +
13161    '    </div>\n' +
13162    '</div>\n' +
13163    '\n' +
13164    '<div class="search-results-show-more" ng-show="hasNextResult()">\n' +
13165    '    <button class="btn-show btn-show_hover search-results-show-more-btn" ng-click="showMore()">Показать ещё</button>\n' +
13166    '</div>\n' +
13167    '');
13168}]);
13169
13170module.exports = "/app/search/directives/search-results/search-results.html";
13171},{}],130:[function(require,module,exports){
13172(function () {
13173    search.$inject = ["$resource"];
13174    angular.module('far.search').factory('Search', search);
13175
13176    function search($resource) {
13177        return $resource('/api/search', {}, {
13178            search: {
13179                method: 'GET'
13180            }
13181        });
13182    }
13183})();
13184
13185},{}],131:[function(require,module,exports){
13186require('./search.module');
13187require('./controllers/climber.controller');
13188require('./controllers/club.controller');
13189require('./controllers/alpclub.controller');
13190require('./controllers/camp.controller');
13191require('./directives/search-block/search-block.directive');
13192require('./controllers/instructor.controller');
13193
13194},{"./controllers/alpclub.controller":114,"./controllers/camp.controller":115,"./controllers/climber.controller":116,"./controllers/club.controller":117,"./controllers/instructor.controller":118,"./directives/search-block/search-block.directive":119,"./search.module":132}],132:[function(require,module,exports){
13195'use strict';
13196
13197require('../core/core');
13198require('../../modules/forms/forms');
13199require('../../modules/pagination/pagination');
13200
13201require('../../models/user/userQualification');
13202require('../../models/user/userAchievements');
13203
13204require('../../models/camp/campCountry');
13205require('../../models/camp/campRegion');
13206require('../../helpers/striptags-filter/striptags.filter');
13207require('angular-resource');
13208require('angular-sanitize');
13209
13210angular.module('far.search', [
13211    'ui.bootstrap',
13212	'far.core',
13213    'dekky.forms',
13214    'dekky.pagination',
13215
13216    'far.models.userQualification',
13217    'far.models.userAchievements',
13218
13219    'far.models.campCountry',
13220    'far.models.campRegion',
13221    'templates',
13222    'far.helpers.stripTagsFilter',
13223    'far.helpers.rawFilter',
13224    'ngResource',
13225    'ngSanitize'
13226])
13227.value('formsConfig', {
13228    theme: '/dekky.forms/themes/far'
13229});
13230
13231},{"../../helpers/striptags-filter/striptags.filter":168,"../../models/camp/campCountry":188,"../../models/camp/campRegion":189,"../../models/user/userAchievements":229,"../../models/user/userQualification":233,"../../modules/forms/forms":244,"../../modules/pagination/pagination":341,"../core/core":38,"angular-resource":2,"angular-sanitize":4}],133:[function(require,module,exports){
13232/**
13233 * Created by PhpStorm on 08.05.2017.
13234 * Author: Shabalin Pavel
13235 * Email: [email protected]
13236 */
13237'use strict';
13238
13239angular.module('far.subclub')
13240    .controller('SubclubEditController', ["$window", "autocomplete", "Subclub", "subclubEditForm", "http", "showModalMessage", function($window, autocomplete, Subclub, subclubEditForm, http, showModalMessage) {
13241
13242        var vm = {
13243            progress: true,
13244            submitted: false,
13245            show_error: true,
13246            subclub: null,
13247            form: {},
13248            fields: subclubEditForm,
13249            constructor: function (subclub) {
13250                if ( subclub ) {
13251                    vm.form = Subclub.get(subclub, function() {
13252                        if ( vm.form.country ) {
13253                            vm.form.country = {
13254                                name: vm.form.country
13255                            };
13256
13257                            vm.fields.autoCompleteSelect.country = vm.form.country_id;
13258                        }
13259
13260                        if ( vm.form.region ) {
13261                            vm.form.region = {
13262                                name: vm.form.region
13263                            };
13264                        }
13265
13266                        if ( vm.form.city ) {
13267                            vm.form.city = {
13268                                name: vm.form.city
13269                            };
13270                        }
13271
13272                        if ( vm.form.parent ) {
13273                            vm.form.club = {
13274                                'id': vm.form.parent.id,
13275                                'name': vm.form.parent.name
13276                            };
13277                        }
13278
13279                        vm.progress = false;
13280                    });
13281                } else {
13282                    vm.form = Subclub.new({country: {
13283                        name: 'Россия',
13284                        id: 150
13285                    }});
13286
13287                    vm.fields.autoCompleteSelect.country = 150;
13288
13289                    vm.progress = false;
13290                }
13291            },
13292            submit: function (form) {
13293                if ( vm.submitted ) {
13294                    return false;
13295                }
13296
13297                if (form.$valid) {
13298                    vm.submitted = true;
13299                    vm.progress = true;
13300
13301                    vm.form.save().then(
13302                        function (response) {
13303                            // Успешно сохранили
13304                            document.location.href=Routing.generate('club_members', {id: response.data.id});
13305                        },
13306                        function (response) {
13307                            response = http.authenticationListener(response);
13308                            vm.submitted = false;
13309                            vm.progress = false;
13310                        }
13311                    );
13312                } else {
13313                    showModalMessage('Форма заполнена не корректно');
13314                }
13315            }
13316        };
13317
13318        vm.fields.$fields.user.uiSelectOptions.onSelect = function(item) {
13319            if (item) { vm.form.user = item; }
13320        };
13321        vm.fields.$fields.club.uiSelectOptions.onSelect = function(item) {
13322            if (item) { vm.form.club = item; }
13323        };
13324        vm.fields.$fields.avatar.uploader.onSuccessItem= function (item, response) {
13325            vm.form.avatar = response;
13326        };
13327        vm.fields.$fields.country.uiSelectOptions.onSelect = function(item) {
13328            if (item) { vm.form.country = item; }
13329        };
13330        vm.fields.$fields.region.uiSelectOptions.onSelect = function(item) {
13331            if (item) { vm.form.region = item; }
13332        };
13333        vm.fields.$fields.city.uiSelectOptions.onSelect = function(item) {
13334            if (item) { vm.form.city = item; }
13335        };
13336
13337        return vm;
13338    }]);
13339
13340},{}],134:[function(require,module,exports){
13341/**
13342 * Created by PhpStorm on 08.05.2017.
13343 * Author: Shabalin Pavel
13344 * Email: [email protected]
13345 */
13346require('./subclub.module');
13347require('./controllers/edit.controller');
13348
13349},{"./controllers/edit.controller":133,"./subclub.module":135}],135:[function(require,module,exports){
13350/**
13351 * Created by PhpStorm on 08.05.2017.
13352 * Author: Shabalin Pavel
13353 * Email: [email protected]
13354 */
13355'use strict';
13356
13357require('../core/core');
13358require('../../modules/pagination/pagination');
13359require('../../modules/forms/forms');
13360
13361require('../../models/user/userMembership');
13362require('../../models/subclub/subclub');
13363
13364require('../../forms/inviteUserForm');
13365require('../../forms/subclubEditForm');
13366require('../../forms/themes/inviteUser/inviteUser.theme');
13367
13368require('../../helpers/show-modal-message/show-modal-message');
13369
13370require('../fos_user/directives/unique-user');
13371
13372angular.module('far.subclub', [
13373    'ngTouch',
13374    'ngMessages',
13375    'angularFileUpload',
13376    'ui.select',
13377    'ui.bootstrap',
13378    'dekky.pagination',
13379    'dekky.forms',
13380    'far.models.userMembership',
13381    'far.models.subclub',
13382    'far.core',
13383    'far.forms.inviteUserForm',
13384    'far.forms.subclubEditForm',
13385    'dekky.forms.themes.inviteUser',
13386    'far.helpers.showModalMessage',
13387    'far.fos_user.uniqueUser'
13388]).value('formsConfig', {
13389    theme: '/dekky.forms/themes/far'
13390});
13391
13392},{"../../forms/inviteUserForm":151,"../../forms/subclubEditForm":156,"../../forms/themes/inviteUser/inviteUser.theme":163,"../../helpers/show-modal-message/show-modal-message":167,"../../models/subclub/subclub":226,"../../models/user/userMembership":232,"../../modules/forms/forms":244,"../../modules/pagination/pagination":341,"../core/core":38,"../fos_user/directives/unique-user":66}],136:[function(require,module,exports){
13393'use strict';
13394angular.module('far.token_users')
13395    .controller('tokenUsersController', ["$log", "$timeout", "$http", "FileUploader", "tokenUsers", "pagination", "form", "fileUploadFilters", "showModalMessage", "$uibModal", function($log,$timeout,$http, FileUploader, tokenUsers, pagination, form, fileUploadFilters, showModalMessage, $uibModal) {
13396        var months=[
13397            {'id':1,'name':"Январь"},
13398            {'id':2,'name':"Февраль"},
13399            {'id':3,'name':"Март"},
13400             {'id':4,'name':"Апрель"},
13401            {'id':5,'name':"Май"},
13402            {'id':6,'name':"Июнь"},
13403             {'id':7,'name':"Июль"},
13404            {'id':8,'name':"Август"},
13405            {'id':9,'name':"Сентябрь"},
13406             {'id':10,'name':"Октябрь"},
13407            {'id':11,'name':"Ноябрь"},
13408            {'id':12,'name':"Декабрь"}
13409            ];
13410
13411        var years=[
13412        {'id':1,'name':"2023"},
13413            {'id':2,'name':"2022"},
13414            {'id':3,'name':"2021"}
13415        ];
13416        var mountain=[
13417            {'id':1,'name':"Эльбрус"},
13418            {'id':2,'name':"Казбек"},
13419            {'id':3,'name':"Белуха"},
13420            
13421        ];
13422        var clubs_all=[];
13423        var club = [];
13424
13425	var vm = {
13426	    progress: true,
13427            submitted: false,
13428            show_error: false,
13429            data: {},
13430            current: {
13431                offset: 0,
13432                limit: 50,
13433                count: 0,
13434                data: []
13435            },
13436            total: {
13437                count: 0,
13438                pages: null
13439            },
13440            
13441            totalPages: 0,
13442            tokenUsersFilter: form('tokenUsersFilter'),
13443            startOffset: 0,
13444            clearFilters: clearFilters,
13445            tokenUsersFilterModel: {
13446                month: null,
13447                year: null,
13448                mountain: mountain[0],
13449                club: null
13450            },
13451            getTokenUsers:getTokenUsers,
13452            form: {},
13453            token_users_show:[],
13454           
13455            submit: function (next, reset) {
13456  
13457                if (vm.submitted) {
13458                    return false;
13459                }
13460                if ( !next ) {
13461                    vm.current.offset = 0;
13462                    vm.current.data = [];
13463                    vm.total.count = 0;
13464                    vm.total.pages = null;
13465                }
13466                var filters = null;
13467
13468                return vm.getTokenUsers(reset).then(function (response) {
13469                    vm.current.data = vm.current.data.concat(response);
13470                    
13471                   // console.log(vm.total.count);
13472                   // console.log(vm.current.data.length);
13473                    vm.total.pages = Math.ceil(vm.total.count / vm.current.limit);
13474                });
13475
13476              
13477
13478            },
13479            
13480            next: function () {
13481                vm.current.offset += vm.current.limit;
13482                vm.submit( true );
13483            },
13484
13485            getTotalCount: function () {
13486                return vm.current.count;
13487            },
13488            constructor: function (year,month) {
13489              //  console.log(month);
13490		      if (month!=null){
13491
13492                for (var i in months){
13493                    if (months[i].id==parseInt(month))
13494                        vm.tokenUsersFilterModel.month=months[i];
13495                }
13496              }
13497              if (year!=null){
13498
13499                for (var i in years){
13500                    if (parseInt(years[i].name)==parseInt(year))
13501                        vm.tokenUsersFilterModel.year=years[i];
13502                }
13503              }
13504
13505                vm.submit();
13506			
13507            }
13508
13509                 };
13510        vm.tokenUsersFilter
13511            .addField('month', 'selectObject', {
13512                validators: {
13513                    required: true
13514                },
13515                options: {
13516                    ngChange: changeData,
13517                    class: 'form__item form__item_select'
13518                },
13519                ngOptions: 'item as item.name for item in field.items track by item.id',
13520                 label: null
13521            }, months)
13522            .addField('year', 'selectObject', {
13523                validators: {
13524                    required: true
13525                },
13526                options: {
13527                    ngChange: changeData,
13528                    class: 'form__item form__item_select'
13529                },
13530                ngOptions: 'item as item.name for item in field.items track by item.id',
13531                label: null
13532            }, years)
13533            .addField('mountain', 'selectObject', {
13534                 ngOptions: 'item as item.name for item in field.items track by item.id',
13535               
13536                label: null,
13537                options: {
13538                    ngChange: changeData,
13539                    class: 'form__item form__item_select'
13540                }
13541            },  mountain)
13542            .addField('last_name', 'text', {
13543                label:null,
13544                options: {
13545                    ngChange: changeData,
13546                    placeholder: 'Фамилия'
13547                },
13548              
13549            })
13550            .addField('num', 'text', {
13551                label:null,
13552                options: {
13553                    ngChange: changeData,
13554                    placeholder: 'Номер'
13555                },
13556               
13557            })
13558            .addField('club', 'selectObject', {
13559                 ngOptions: 'item as item.name for item in field.items track by item.id',
13560               
13561                label: null,
13562                options: {
13563                    ngChange: changeData,
13564                    class: 'form__item form__item_select',
13565                    placeholder: "Организация"
13566                }
13567            },  club);
13568
13569        function changeData() {
13570            $timeout(function() {
13571            vm.submit();
13572            });
13573            
13574        }
13575       
13576     function getFilters(reset) {
13577              //  console.log('model',vm.tokenUsersFilterModel);
13578              //  console.log('fields',vm.tokenUsersFilter);
13579            if (reset)
13580                vm.tokenUsersFilterModel = {
13581                            month: null,
13582                            year: null,
13583                            mountain: mountain[0],
13584                            club: null,
13585                            num: null,
13586                            last_name: null
13587                        };
13588            return {
13589                num:  vm.tokenUsersFilterModel.num ?  vm.tokenUsersFilterModel.num : null,
13590                last_name:  vm.tokenUsersFilterModel.last_name ?  vm.tokenUsersFilterModel.last_name : null,
13591                mountain:  vm.tokenUsersFilterModel.mountain ?  vm.tokenUsersFilterModel.mountain.name : null,
13592                month: vm.tokenUsersFilterModel.month ? vm.tokenUsersFilterModel.month.name : null,
13593                year:vm.tokenUsersFilterModel.year ? vm.tokenUsersFilterModel.year.name : null,
13594                club:vm.tokenUsersFilterModel.club ? vm.tokenUsersFilterModel.club.name : null,
13595
13596            }
13597
13598        }
13599
13600        function clearFilters(){
13601         
13602           vm.submit(false,true);
13603        }
13604       
13605        function getTokenUsers(reset) {
13606
13607            var data = angular.merge({}, getFilters(reset));
13608            
13609
13610            data['offset'] = vm.current.offset;
13611            data['limit'] = vm.current.limit;
13612
13613            return $http.get(Routing.generate('api_entities_get_token_users',
13614                data
13615            )).then(function(response) {
13616                vm.total.count =  response.headers('X-Total-Count');
13617                var items = [];
13618                //console.log('get_mountainroutes',response.data);
13619                angular.forEach(response.data[0], function(item) {
13620                    items.push(item);
13621
13622                });
13623
13624                vm.data=items;
13625                
13626                if (clubs_all.length==0){
13627                
13628                angular.forEach(response.data[1], function(item) {
13629                    clubs_all.push(item);
13630
13631                });
13632
13633                for (var i in clubs_all)
13634                    if (clubs_all[i]["club"]!=null && clubs_all[i]["club"]!="")
13635                    club.push({"id":i,"name":clubs_all[i]["club"]});
13636                }
13637                
13638               
13639                return items;
13640            }).catch(function(response) {
13641                $log.error(response);
13642                return $q.reject(response);
13643            })
13644        }
13645       
13646        return vm;
13647    }]);
13648
13649},{}],137:[function(require,module,exports){
13650require('./token_users.module');
13651require('./controllers/token_users.controller');
13652
13653},{"./controllers/token_users.controller":136,"./token_users.module":138}],138:[function(require,module,exports){
13654'use strict';
13655
13656require('../core/core');
13657require('../../modules/pagination/pagination');
13658require('../../modules/forms/forms');
13659require('../../modules/gallery/gallery');
13660
13661require('../../models/token_users/token_users');
13662
13663require('../../modals/slider/slider');
13664
13665require('../../helpers/show-modal-message/show-modal-message');
13666
13667angular.module('far.token_users', [
13668	'ngTouch',
13669	'angularFileUpload',
13670	'ui.select',
13671	'ui.bootstrap',
13672	'dekky.pagination',
13673	'dekky.forms',
13674	'far.models.token_users',
13675	'far.gallery',
13676	'far.core',
13677	'far.modals.slider',
13678	'far.helpers.showModalMessage',
13679	'templates'
13680]).value('formsConfig', {
13681	theme: '/dekky.forms/themes/far'
13682});
13683
13684},{"../../helpers/show-modal-message/show-modal-message":167,"../../modals/slider/slider":182,"../../models/token_users/token_users":227,"../../modules/forms/forms":244,"../../modules/gallery/gallery":332,"../../modules/pagination/pagination":341,"../core/core":38}],139:[function(require,module,exports){
13685(function($) {
13686        $('body').on('click', '.image-crop-init', function () {
13687            $('#img-crop').cropper('destroy');
13688
13689            $('#img-crop').cropper({
13690                 aspectRatio: 4/3,
13691		dragMode: 'move',
13692                crop: function (e) {
13693                },
13694
13695            });
13696        });
13697
13698        $('body').on('click', '.image-crop-destroy', function () {
13699            $('#img-crop').cropper('destroy');
13700        });
13701
13702        $('body').on('click', '.image-crop-save', function () {
13703            var dimData = $('#img-crop').cropper('getData');
13704            var imData = $('#img-crop').cropper('getImageData');
13705
13706
13707            var cropData = {
13708                imageId: $('#img-crop').attr('data-image-id'),
13709                x: dimData.x,
13710                y: dimData.y,
13711                width: dimData.width,
13712                height: dimData.height,
13713		wo: imData.naturalWidth,
13714		ho: imData.naturalHeight,
13715		wn: imData.width,
13716		hn: imData.height
13717            };
13718
13719            $.post( "/api/avatars/crops", cropData)
13720                .done(function( response ) {
13721                    $('.btn-form-save').trigger('click');
13722                });
13723        });
13724
13725})(jQuery);
13726
13727},{}],140:[function(require,module,exports){
13728'use strict';
13729
13730require('../modules/forms/forms');
13731require('../models/ascent/ascentTypes');
13732require('../models/ascent/ascentUserTypes');
13733require('../models/mountains/regions');
13734require('../helpers/show-modal-message/show-modal-message');
13735
13736angular.module('far.forms.ascentEditForm', [
13737	'dekky.forms',
13738	'far.models.ascentTypes',
13739	'far.models.ascentUserTypes',
13740	'far.models.mountains.regions',
13741	'far.helpers.showModalMessage'
13742])
13743.service('ascentEditForm', ["form", "ascentTypes", "ascentUserTypes", "mountainReg
13743ions", "autocomplete", "fileUploadFilters", "showModalMessage", function(form, ascentTypes,ascentUserTypes, mountainRegions, autocomplete, fileUploadFilters, showModalMessage) {
13744	function formFactory() {
13745		var ascentEditModel = form('ascentEditModel');
13746
13747		ascentEditModel
13748			.addField('ascent_date', 'dateDropdowns', {
13749				validators: { required: false },
13750				label_before: 'Дата восхождения:',
13751				label_before_class: 'form__comment'
13752			})
13753			.addField('ascent_type', 'selectObject', {
13754				validators: { required: false },
13755				options: { defaultOption: 'Способ восхождения' },
13756				ngOptions: 'item as item.name for item in field.items track by item.id'
13757			}, ascentTypes.list)
13758            .addField('ascent_user_type', 'selectObject', {
13759                validators: { required: true },
13760                options: {defaultOption: 'Роль'},
13761                ngOptions: 'item as item.name for item in field.items track by item.id'
13762            }, ascentUserTypes.list)
13763			.addField('master_selector', 'radioCollection', {
13764				validators:{required:false},
13765				radio:{label: 'name'},
13766				radioAttributes:{
13767					ngClick: 'field.ngClick(item, field)'
13768				},
13769				fieldData:{
13770					ngClick: function (item, field) {
13771						field.radioAttributes.onSelect(item);
13772                    }
13773				}
13774			},[{model:'chief', name:'Руководитель'},{model:'instructor', name:'Инструктор'}])
13775			.addField('first_ascent', 'checkbox', {
13776				label: 'Первопрохождение'
13777			})
13778			.addField('first_climb', 'checkbox', {
13779				label: 'Первовосхождение'
13780			})
13781
13782			.addField('ascent_mountain_peak', 'mountainPeakSelect')
13783
13784			.addField('ascent_mountain_route', 'selectObject', {
13785				validators: {
13786					required: true
13787				},
13788				options: {
13789					defaultOption: 'Выберите маршрут...',
13790					onSelect: 'field.uiSelectOptions.onSelect($item)'
13791				},
13792                ngOptions: 'item as item.name + " / " +item.mountain_route_complexity.name  for item in field.items track by item.id'
13793			}, [])
13794			.addField('user_chief', 'userSelect', {
13795				uiSelectOptions: {
13796          match: {
13797            placeholder: 'Выберите руководителя...'
13798          },
13799					choices: {
13800						refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "users")'
13801					},
13802					refreshAutoComplete: autocomplete.refreshAutoComplete
13803				}
13804			}, autocomplete.get('users'))
13805      .addField('user_participant', 'userSelect', {
13806        uiSelectOptions: {
13807          match: {
13808            placeholder: 'Выберите участника...'
13809          },
13810          choices: {
13811            refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userParticipants")'
13812          },
13813          refreshAutoComplete: autocomplete.refreshAutoComplete
13814        }
13815      }, autocomplete.get('userParticipants'))
13816            .addField('user_instructor', 'userSelect', {
13817                uiSelectOptions: {
13818                    match: {
13819                        placeholder: 'Выберите инструктора...'
13820                    },
13821                    choices: {
13822                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Instructors", "userInstructors")'
13823                    },
13824                    refreshAutoComplete: autocomplete.refreshAutoComplete
13825                }
13826            }, autocomplete.get('userInstructors'))
13827			.addField('documentsFiles', 'fileUpload', {
13828				validators: {
13829					required: false
13830				},
13831				label: 'Загрузить документ',
13832				uploader: {
13833					url: Routing.generate('api_upload_post_file'),
13834					autoUpload: true,
13835					filters: [
13836						fileUploadFilters.fileSize(),
13837						fileUploadFilters.fileType()
13838					],
13839					onSuccessItem: function (item, response) {
13840						item.serverData = response;
13841					},
13842					onWhenAddingFileFailed: function(item, filter) {
13843						var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
13844						showModalMessage(message);
13845					}
13846				},
13847				fieldData: {
13848					getUrl: function(item) {
13849						if ( item.serverData !== undefined ) {
13850							return Routing.generate('api_upload_get_file', {fileStorage: item.serverData.id});
13851						}
13852					}
13853				}
13854			});
13855
13856		return ascentEditModel;
13857	}
13858
13859	return formFactory;
13860}]);
13861
13862},{"../helpers/show-modal-message/show-modal-message":167,"../models/ascent/ascentTypes":183,"../models/ascent/ascentUserTypes":184,"../models/mountains/regions":214,"../modules/forms/forms":244}],141:[function(require,module,exports){
13863'use strict';
13864
13865require('../modules/forms/forms');
13866require('../helpers/show-modal-message/show-modal-message');
13867
13868angular.module('far.forms.clubEditForm', ['dekky.forms', 'far.helpers.showModalMessage'])
13869    .service('clubEditForm', ["form", "autocomplete", "showModalMessage", function(form, autocomplete, showModalMessage) {
13870        var autoCompleteSelect = {
13871            country: null,
13872            region: null,
13873            city: null
13874        };
13875
13876        var clubForm = form('club');
13877
13878        clubForm
13879            .addField('name', 'text', {
13880                validators: {
13881                    required: true
13882                },
13883                options: {
13884                    placeholder: 'Название'
13885                }
13886            })
13887            .addField('country', 'uiSelect', {
13888                validators: {
13889                    required: false
13890                },
13891                options: {
13892                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
13893                    class: 'form__ui-select width-650'
13894                },
13895                uiSelectOptions: {
13896                    matchTitle: '{{ $select.selected.name }} ',
13897                    choicesTitle: '{{ item.name }}',
13898                    match: {
13899                        placeholder: 'Страна',
13900                        allowClear: true
13901                    },
13902                    choices: {
13903                        repeat: 'item in field.items track by item.id',
13904                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Country", "country")',
13905                        refreshDelay: 0
13906                    },
13907                    refreshAutoComplete: autocomplete.refreshAutoComplete,
13908                    onSelect: function( item ) {
13909                        if ( item ) {
13910                            autoCompleteSelect.country = item.id;
13911                            autoCompleteSelect.region = null;
13912                            autoCompleteSelect.city = null;
13913
13914                            clubForm.$fields.region.items = [];
13915                            clubForm.$fields.city.items = [];
13916                        }
13917                    }
13918                }
13919            }, autocomplete.get('country'))
13920            .addField('region', 'uiTypeahead', {
13921                validators: {
13922                    required: false
13923                },
13924                options: {
13925                    class: 'form__item',
13926                    placeholder: 'Регион',
13927                    uibTypeahead: "row as row.name for row in field.refreshAutoComplete($viewValue, 'Region')"
13928                },
13929                fieldData: {
13930                    clearBtn: true,
13931                    refreshAutoComplete: function(name, term) {
13932                        return autocomplete.refreshAutoComplete(name, term, null, autoCompleteSelect)
13933                    }
13934                }
13935            })
13936            .addField('city', 'uiTypeahead', {
13937                validators: {
13938                    required: false
13939                },
13940                options: {
13941                    class: 'form__item',
13942                    placeholder: 'Населенный пункт',
13943                    uibTypeahead: "row as row.name for row in field.refreshAutoComplete($viewValue, 'City')"
13944                },
13945                fieldData: {
13946                    clearBtn: true,
13947                    refreshAutoComplete: function(name, term) {
13948                        return autocomplete.refreshAutoComplete(name, term, null, autoCompleteSelect)
13949                    }
13950                }
13951            })
13952            .addField('address', 'text', {
13953                validators: {
13954                    required: false
13955                },
13956                options: {
13957                    placeholder: 'Адрес'
13958                }
13959            })
13960            .addField('phone', 'text', {
13961                validators: {
13962                    required: false
13963                },
13964                options: {
13965                    placeholder: 'Телефон'
13966                }
13967            })
13968            .addField('email', 'text', {
13969                validators: {
13970                    required: false
13971                },
13972                options: {
13973                    placeholder: 'E-mail'
13974                }
13975            })
13976            .addField('www', 'text', {
13977                validators: {
13978                    required: false
13979                },
13980                options: {
13981                    placeholder: 'Сайт'
13982                }
13983            })
13984            .addField('user', 'userSelect', {
13985                validators: {
13986                    required: true
13987                },
13988                uiSelectOptions: {
13989                    match: {
13990                        placeholder: 'Имя и фамилия руководителя'
13991                    }
13992                }
13993            }, autocomplete.get('users'))
13994            .addField('avatar', 'imageUpload', {
13995                validators: {
13996                    required: false
13997                },
13998                uploader: {
13999                    url: Routing.generate('api_upload_post_avatar', {thumb: 'avatar_relative'}),
14000                    autoUpload: true,
14001                    removeAfterUpload: true,
14002                    onWhenAddingFileFailed: function(item, filter) {
14003              				var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
14004                      showModalMessage(message);
14005              			},
14006              			onErrorItem: function() {
14007          			      showModalMessage('Невозможно загрузить файл на сервер');              				
14008              			}
14009                }
14010            })
14011            .addField('social_vk', 'text', {
14012                validators: {
14013                    required: false
14014                },
14015                options: {
14016                    placeholder: 'Вконтакте'
14017                }
14018            })
14019            .addField('social_fb', 'text', {
14020                validators: {
14021                    required: false
14022                },
14023                options: {
14024                    placeholder: 'Facebook'
14025                }
14026            })
14027            .addField('social_in', 'text', {
14028                validators: {
14029                    required: false
14030                },
14031                options: {
14032                    placeholder: 'Instagram'
14033                }
14034            })
14035            ;
14036
14037        return clubForm;
14038    }]);
14039
14040},{"../helpers/show-modal-message/show-modal-message":167,"../modules/forms/forms":244}],142:[function(require,module,exports){
14041'use strict';
14042
14043require('../modules/forms/forms');
14044require('./partnerFromUserForm');
14045require('../models/discipline/discipline');
14046require('../models/competition/competitionType');
14047require('../models/partners/partners');
14048require('../helpers/show-modal-message/show-modal-message');
14049
14050angular.module('far.forms.competitionReportForm', [
14051        'dekky.forms',
14052        'far.forms.partnerFromUserForm',
14053        'far.models.discipline',
14054        'far.models.competition.competitionType',
14055        'far.models.partners',
14056        'far.helpers.showModalMessage'
14057    ])
14058    .service('competitionReportForm', ["form", "partnerFromUserForm", "fileUploadFilters", "Discipline", "partners", "showModalMessage", "autocomplete", "CompetitionType", function (form, partnerFromUserForm, fileUploadFilters, Discipline, partners, showModalMessage, autocomplete, CompetitionType) {
14059        var competitionReportForm = form('competitionReportForm');
14060        var competitionTypeList = CompetitionType.list;
14061
14062        competitionReportForm
14063            .addField('participants_male', null, {
14064                validators: {
14065                    required: true,
14066                    numericOnly: '',
14067                    class: 'form__item width-50'
14068                }
14069            })
14070            .addField('participants_female', null, {
14071                validators: {
14072                    required: true,
14073                    numericOnly: '',
14074                    class: 'form__item width-50'
14075                }
14076            })
14077            .addField('safety', 'userSelect', {
14078                validators: {
14079                    required: true
14080                },
14081                options: {
14082                    class: 'form__ui-select'
14083                },
14084                uiSelectOptions: {
14085                    match: {
14086                        placeholder: 'Ответственный за безопасность, ФИО'
14087                    },
14088                    choices: {
14089                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "safety")'
14090                    },
14091                    refreshAutoComplete: autocomplete.refreshAutoComplete
14092                }
14093            }, autocomplete.get('safety'))
14094            .addField('judge', 'userSelect', {
14095                validators: {
14096                    required: true
14097                },
14098                options: {
14099                    class: 'form__ui-select'
14100                },
14101                uiSelectOptions: {
14102                    match: {
14103                        placeholder: 'Судья, ФИО'
14104                    },
14105                    choices: {
14106                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "judge")'
14107                    },
14108                    refreshAutoComplete: autocomplete.refreshAutoComplete
14109                }
14110            }, autocomplete.get('judge'))
14111            .addField('winner', 'userSelect', {
14112                validators: {
14113                    required: false
14114                },
14115                options: {
14116                    class: 'form__ui-select'
14117                },
14118                uiSelectOptions: {
14119                    match: {
14120                        placeholder: 'ФИО',
14121                        allowClear: true
14122                    },
14123                    choices: {
14124                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "winner")'
14125                    },
14126                    refreshAutoComplete: autocomplete.refreshAutoComplete
14127                }
14128            }, autocomplete.get('winner'))
14129            .addField('documentsFiles', 'fileUpload', {
14130                validators: {
14131                    required: false
14132                },
14133                label: 'Загрузить файл',
14134                uploader: {
14135                    url: Routing.generate('api_upload_post_file'),
14136                    autoUpload: true,
14137                    filters: [
14138                        fileUploadFilters.fileSize(),
14139                        fileUploadFilters.fileType()
14140                    ],
14141                    onSuccessItem: function (item, response) {
14142                        item.serverData = response;
14143                    },
14144                    onWhenAddingFileFailed: function (item, filter) {
14145                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
14146                        showModalMessage(message);
14147                    }
14148                }
14149            });
14150
14151        return competitionReportForm;
14152    }]);
14153
14154},{"../helpers/show-modal-message/show-modal-message":167,"../models/compet
14154ition/competitionType":194,"../models/discipline/discipline":196,"../models/partners/partners":222,"../modules/forms/forms":244,"./partnerFromUserForm":154}],143:[function(require,module,exports){
14155'use strict';
14156
14157require('../modules/forms/forms');
14158require('./partnerFromUserForm');
14159require('../models/discipline/discipline');
14160require('../models/competition/competitionType');
14161require('../models/event/eventStatus');
14162require('../models/partners/partners');
14163require('../helpers/show-modal-message/show-modal-message');
14164
14165angular.module('far.forms.competitionRequestForm', [
14166        'dekky.forms',
14167        'far.forms.partnerFromUserForm',
14168        'far.models.discipline',
14169        'far.models.competition.competitionType',
14170        'far.models.event.status',
14171        'far.models.partners',
14172        'far.helpers.showModalMessage'
14173    ])
14174    .service('competitionRequestForm', ["form", "partnerFromUserForm", "fileUploadFilters", "Discipline", "partners", "showModalMessage", "autocomplete", "CompetitionType", "eventStatus", function (form, partnerFromUserForm, fileUploadFilters, Discipline, partners, showModalMessage, autocomplete, CompetitionType, eventStatus) {
14175        var competitionRequestForm = form('competitionRequestForm');
14176        var competitionTypeList = CompetitionType.list;
14177
14178        competitionRequestForm
14179            .addField('accepted', 'selectObject', {
14180                validators: {
14181                    required: true
14182                },
14183                options: {
14184                    defaultOption: 'Статус соревнования',
14185                    class: 'form__item form__item_select width-350'
14186                },
14187                ngOptions: 'item as item.status for item in field.items track by item.id'
14188            }, eventStatus.list)
14189            .addField('disciplines', 'selectObject', {
14190                validators: {
14191                    required: true
14192                },
14193                options: {
14194                    defaultOption: 'Дисциплина',
14195                    class: 'form__item form__item_select width-350',
14196                    ngChange: 'field.ngChange(model)'
14197                },
14198                ngOptions: 'item as item.name for item in field.items track by item.id',
14199                fieldData: {
14200                    ngChange: function (item) {
14201                        if (angular.isObject(item)) {
14202                            competitionRequestForm.$fields.event_competition_type.items = competitionTypeList[item.system_name];
14203                        }
14204                    }
14205                }
14206            }, Discipline.list)
14207            .addField('event_competition_type', 'checkboxCollection', {
14208                checkbox: {
14209                    label: 'name',
14210                    model: 'selected'
14211                },
14212                checkboxAttributes: {
14213                    ngChange: 'field.ngChange(item, field)'
14214                },
14215                fieldData: {
14216                    ngChange: function (item, field) {
14217
14218                    }
14219                }
14220            }, [])
14221            .addField('date_from', 'dateDropdowns', {
14222                validators: {
14223                    required: true
14224                }
14225            })
14226            .addField('date_to', 'dateDropdowns', {
14227                validators: {
14228                    required: true
14229                }
14230            })
14231            .addField('location', null, {
14232                validators: {
14233                    required: true
14234                }
14235            })
14236            .addField('camp', 'uiSelect', {
14237                validators: {
14238                    required: false
14239                },
14240                options: {
14241                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
14242                    class: 'form__ui-select width-600'
14243                },
14244                uiSelectOptions: {
14245                    matchTitle: '{{ $select.selected.name }} ',
14246                    choicesTitle: '{{ item.name }}',
14247                    match: {
14248                        placeholder: 'Альплагерь',
14249                        allowClear: true
14250                    },
14251                    choices: {
14252                        repeat: 'item in field.items track by item.id',
14253                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Camp", "camp")',
14254                        refreshDelay: 0
14255                    },
14256                    refreshAutoComplete: autocomplete.refreshAutoComplete
14257                }
14258            }, autocomplete.get('camp'))
14259            .addField('name', null, {
14260                validators: {
14261                    required: true
14262                },
14263                options: {
14264                    placeholder: 'Название соревнования',
14265                    class: 'form__item'
14266                }
14267            })
14268            .addField('brief', 'textarea', {
14269                validators: {
14270                    required: true
14271                },
14272                options: {
14273                    placeholder: 'Анонс',
14274                    class: 'form__item',
14275                    maxlength: 150
14276                }
14277            })
14278            .addField('description', 'textarea', {
14279                validators: {
14280                    required: true
14281                },
14282                options: {
14283                    redactor: true,
14284                    placeholder: 'Ваше описание',
14285                    class: 'form__item'
14286                }
14287            })
14288            .addField('club', 'uiSelect', {
14289                validators: {
14290                    required: true
14291                },
14292                options: {
14293                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
14294                    class: 'form__ui-select'
14295                },
14296                uiSelectOptions: {
14297                    matchTitle: '{{ $select.selected.name }} ',
14298                    choicesTitle: '{{ item.name }}',
14299                    match: {
14300                        placeholder: 'Федерация / Клуб',
14301                        allowClear: true
14302                    },
14303                    choices: {
14304                        repeat: 'item in field.items track by item.id',
14305                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Club", "club")',
14306                        refreshDelay: 0
14307                    },
14308                    refreshAutoComplete: autocomplete.refreshAutoComplete
14309                }
14310            }, autocomplete.get('club'))
14311            .addField('user_director', 'userSelect', {
14312                validators: {
14313                    required: true
14314                },
14315                options: {
14316                    class: 'form__ui-select'
14317                },
14318                uiSelectOptions: {
14319                    match: {
14320                        placeholder: 'Директор, ФИО'
14321                    },
14322                    choices: {
14323                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "user_director")'
14324                    },
14325                    refreshAutoComplete: autocomplete.refreshAutoComplete
14326                }
14327            }, autocomplete.get('user_director'))
14328            .addField('user_main_judge', 'userSelect', {
14329                validators: {
14330                    required: true
14331                },
14332                options: {
14333                    class: 'form__ui-select'
14334                },
14335                uiSelectOptions: {
14336                    match: {
14337                        placeholder: 'Главный судья, ФИО'
14338                    },
14339                    choices: {
14340                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "user_main_judge")'
14341                    },
14342                    refreshAutoComplete: autocomplete.refreshAutoComplete
14343                }
14344            }, autocomplete.get('user_main_judge'))
14345            .addField('partners', 'checkboxCollection', {
14346                options: {
14347                    class: 'form-group_quarter'
14348                },
14349                checkbox: {
14350                    label: 'name',
14351                    model: 'selected'
14352                }
14353            }, partners.list)
14354            .addField('documentsFiles', 'fileUpload', {
14355                validators: {
14356                    required: true
14357                },
14358                label: 'Загрузить файл',
14359                uploader: {
14360                    url: Routing.generate('api_upload_post_file'),
14361                    autoUpload: true,
14362                    filters: [
14363                        fileUploadFilters.fileSize(),
14364                        fileUploadFilters.fileType()
14365                    ],
14366                    onSuccessItem: function (item, response) {
14367                        item.serverData = response;
14368                    },
14369                    onWhenAddingFileFailed: function (item, filter) {
14370                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
14371                        showModalMessage(message);
14372                    }
14373                }
14374            })
14375            .addField('backgroundImage', 'imageUpload', {
14376                validators: {
14377                    required: true
14378                },
14379                label: 'Загрузить фото',
14380                uploader: {
14381                    url: Routing.generate('api_upload_post_image'),
14382                    autoUpload: true,
14383                    queueLimit: 1,
14384                    onSuccessItem: function (item, response) {
14385                        item.serverData = response;
14386                    },
14387                    onWhenAddingFileFailed: function (item, filter) {
14388                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
14389
14390                        if (filter.name == 'queueLimit') {
14391                            message = 'Вы можете загрузить только одно фоновое изображение';
14392                        }
14393
14394                        showModalMessage(message);
14395                    }
14396                }
14397            });
14398
14399        return competitionRequestForm;
14400    }]);
14401
14402},{"../helpers/show-modal-message/show-modal-message":167,"../models/compet
14402ition/competitionType":194,"../models/discipline/discipline":196,"../models/event/eventStatus":210,"../models/partners/partners":222,"../modules/forms/forms":244,"./partnerFromUserForm":154}],144:[function(require,module,exports){
14403'use strict';
14404
14405require('../modules/forms/forms');
14406
14407angular.module('far.forms.educationGalleryForm', ['dekky.forms'])
14408    .service('educationGalleryForm', ["form", "fileUploadFilters", function(form, fileUploadFilters) {
14409        var eventGalleryForm = form('educationGallery');
14410
14411        eventGalleryForm
14412            .addField('slides_files', 'imageUpload', {
14413                validators: { required: true },
14414                label: 'Загрузить изображение',
14415                fieldData: {
14416                    multipleUpload: 'true'
14417                },
14418                uploader: {
14419                    url: Routing.generate('api_upload_post_image'),
14420                    filters: [
14421                        fileUploadFilters.fileSize()
14422                    ],
14423                    autoUpload: true,
14424                    removeAfterUpload: true
14425                }
14426            });
14427
14428        return eventGalleryForm;
14429    }]);
14430
14431},{"../modules/forms/forms":244}],145:[function(require,module,exports){
14432'use strict';
14433
14434require('../models/ascent/ascentTypes');
14435require('../helpers/show-modal-message/show-modal-message');
14436
14437angular.module('far.forms.educationReportForm', [
14438    'dekky.forms',
14439    'far.models.ascentTypes',
14440    'far.helpers.showModalMessage'
14441])
14442.service('educationReportForm', ["form", "autocomplete", "ascentTypes", "fileUploadFilters", "showModalMessage", function(
14443    form,
14444    autocomplete,
14445    ascentTypes,
14446    fileUploadFilters,
14447    showModalMessage
14448) {
14449    var reportModel = form('educationReportModel');
14450    var ascentModel = form('ascentModel');
14451    var userModel = form('userModel');
14452
14453    userModel
14454        .addField('fio', 'uiTypeahead', {
14455            validators: {
14456                required: true
14457            },
14458            options: {
14459                placeholder: 'Участник',
14460                class: 'form__item width-350 margin_r_20',
14461                uibTypeahead: "row for row in field.refreshAutoComplete($viewValue, 'Users')",
14462                typeaheadOnSelect: 'field.userSelect($item, $model, $label, $event, fieldData)',
14463                typeaheadTemplateUrl: '/dekky.forms/themes/typeaheadUser/typeahead-match.html',
14464                typeaheadInputFormatter: 'field.formatLabel($model)'
14465            },
14466            fieldData: {
14467                clearBtn: true,
14468                refreshAutoComplete: function(name, term) {
14469                    return autocomplete.refreshAutoComplete(name, term);
14470                },
14471                userSelect: function($item, $model, $label, $event, parentItem) {
14472                    parentItem.email = $item.email;
14473                },
14474                formatLabel: function($model) {
14475                    if (angular.isObject($model)) {
14476                        return $model.fio;
14477                    } else {
14478                        return $model;
14479                    }
14480                }
14481            }
14482        }, autocomplete.get('ascentUsers'))
14483        .addField('email', null, {
14484            validators: {
14485                required: true
14486            },
14487            options: {
14488                class: 'form__item width-350',
14489                placeholder: 'E-mail участника'
14490            }
14491        });
14492
14493    ascentModel
14494        .addField('ascent_date', 'dateDropdowns', {
14495            validators: { required: true }
14496        })
14497        .addField('ascent_mountain_peak', 'mountainPeakSelect', {
14498            options: {
14499                class: 'form__ui-select width-350'
14500            }
14501        })
14502        .addField('ascent_mountain_route', 'selectObject', {
14503            validators: {
14504                required: true
14505            },
14506            options: {
14507                defaultOption: 'Маршрут',
14508                onSelect: 'field.uiSelectOptions.onSelect($item)',
14509                class: 'form__item form__item_select width-350 margin_r_20'
14510            },
14511            ngOptions: 'item as item.name + " / " +item.mountain_route_complexity.name  for item in field.items track by item.id'
14512        }, [])
14513        .addField('ascent_type', 'selectObject', {
14514            validators: { required: false },
14515            options: {
14516                defaultOption: 'Способ восхождения',
14517                class: 'form__item width-350 margin_r_20 form__item_select'
14518            },
14519            ngOptions: 'item as item.name for item in field.items track by item.id'
14520        }, ascentTypes.list)
14521        .addField('instructor', 'userSelect', {
14522            validators: { required: false },
14523            options: {
14524                class: 'form__ui-select width-350 margin_b_20'
14525            },
14526            uiSelectOptions: {
14527                match: {
14528                    placeholder: 'Инструктор'
14529                },
14530                choices: {
14531                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "instructor")'
14532                },
14533                refreshAutoComplete: autocomplete.refreshAutoComplete
14534            }
14535        }, autocomplete.get('instructor'))
14536        .addField('user_chief', 'userSelect', {
14537            validators: { required: false },
14538            options: {
14539                class: 'form__ui-select width-350 margin_b_20'
14540            },
14541            uiSelectOptions: {
14542                match: {
14543                    placeholder: 'Руководитель'
14544                },
14545                choices: {
14546                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userСhief")'
14547                },
14548                refreshAutoComplete: autocomplete.refreshAutoComplete
14549            }
14550        }, autocomplete.get('userСhief'))
14551        .addField('ascent_users', 'collection', {
14552            buttons: {
14553                add: 'Добавить участника',
14554                remove: 'Удалить'
14555            }
14556        }, userModel);
14557
14558    reportModel
14559        .addField('club', 'uiSelect', {
14560            validators: {
14561                required: true
14562            },
14563            options: {
14564                onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
14565                class: 'form__ui-select width-600'
14566            },
14567            uiSelectOptions: {
14568                matchTitle: '{{ $select.selected.name }} ',
14569                choicesTitle: '{{ item.name }}',
14570                match: {
14571                    placeholder: 'Федерация / Клуб',
14572                    allowClear: true
14573                },
14574                choices: {
14575                    repeat: 'item in field.items track by item.id',
14576                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Club", "club")',
14577                    refreshDelay: 0
14578                },
14579                refreshAutoComplete: autocomplete.refreshAutoComplete
14580            }
14581        }, autocomplete.get('club'))
14582        .addField('userChief', 'userSelect', {
14583            options: {
14584                class: 'form__ui-select width-350'
14585            },
14586            uiSelectOptions: {
14587                match: {
14588                    placeholder: 'Организатор, ФИО',
14589                    allowClear: true
14590                },
14591                choices: {
14592                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userChiefs")'
14593                },
14594                refreshAutoComplete: autocomplete.refreshAutoComplete
14595            }
14596        }, autocomplete.get('userChiefs'))
14597        .addField('userCoach', 'userSelect', {
14598            options: {
14599                class: 'form__ui-select width-350'
14600            },
14601            uiSelectOptions: {
14602                match: {
14603                    placeholder: 'Старший тренер',
14604                    allowClear: true
14605                },
14606                choices: {
14607                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userCoaches")'
14608                },
14609                refreshAutoComplete: autocomplete.refreshAutoComplete
14610            }
14611        }, autocomplete.get('userCoaches'))
14612        .addField('userSafety', 'userSelect', {
14613            options: {
14614                class: 'form__ui-select width-350'
14615            },
14616            uiSelectOptions: {
14617                match: {
14618                    placeholder: 'Ответственный за безопасность, ФИО',
14619                    allowClear: true
14620                },
14621                choices: {
14622                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userSafeties")'
14623                },
14624                refreshAutoComplete: autocomplete.refreshAutoComplete
14625            }
14626        }, autocomplete.get('userSafeties'))
14627        .addField('userInstructor', 'userSelect', {
14628            uiSelectOptions: {
14629                match: {
14630                    allowClear: true
14631                },
14632                choices: {
14633                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userInstructor")'
14634                },
14635                refreshAutoComplete: autocomplete.refreshAutoComplete
14636            }
14637        }, autocomplete.get('userInstructor'))
14638        .addField('userJuniorInstructor', 'userSelect', {
14639            uiSelectOptions: {
14640                match: {
14641                    allowClear: true
14642                },
14643                choices: {
14644                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userJuniorInstructor")'
14645                },
14646                refreshAutoComplete: autocomplete.refreshAutoComplete
14647            }
14648        }, autocomplete.get('userJuniorInstructor'))
14649        .addField('countUsersTotal', null, {
14650            'validators': {
14651                required: false,
14652                numericOnly: ''
14653            }
14654        })
14655        .addField('users_complite', 'collection', {
14656            buttons: {
14657                add: 'Добавить участника',
14658                remove: 'Удалить'
14659            }
14660        }, userModel)
14661        /*.addField('countUsersCc', null, {
14662            'validators': {
14663                required: true,
14664                numericOnly: ''
14665            }
14666        })
14667        .addField('countUsersCp', null, {
14668            'validators': {
14669                required: true,
14670                numericOnly: ''
14671            }
14672        })
14673        .addField('countUsersNp', null, {
14674            'validators': {
14675                required: true,
14676                numericOnly: ''
14677            }
14678        })
14679        .addField('countUsersCm', null, {
14680            'validators': {
14681                required: true,
14682                numericOnly: ''
14683            }
14684        })*/
14685        .addField('documentsFiles', 'fileUpload', {
14686            validators: {
14687                required: true
14688            },
14689            label: 'Загрузить файл',
14690            uploader: {
14691                url: Routing.generate('api_upload_post_file'),
14692                autoUpload: true,
14693                filters: [
14694                    fileUploadFilters.fileSize(),
14695                    fileUploadFilters.fileType()
14696                ],
14697                onSuccessItem: function (item, response) {
14698                    item.serverData = response;
14699                },
14700                onWhenAddingFileFailed: function(item, filter) {
14701                    var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
14702                    showModalMessage(message);
14703                }
14704            }
14705        })
14706        .addField('ascents', 'collection', {
14707            buttons: {
14708                add: 'Добавить восхождение',
14709                remove: 'Удалить восхождение',
14710                save: 'Сохранить'
14711            }
14712        }, ascentModel);
14713
14714    return reportModel;
14715}]);
14716
14717},{"../helpers/show-modal-message/show-modal-message":167,"../models/ascent/ascentTypes":183}],146:[function(require,module,exports){
14718'use strict';
14719
14720require('../modules/forms/forms');
14721require('../models/education/educationDiscipline');
14722require('../models/education/educationStatus');
14723require('../models/education/educationQualificationGroup');
14724require('../models/partners/partners');
14725require('./partnerFromUserForm');
14726require('../helpers/show-modal-message/show-modal-message');
14727
14728angular.module('far.forms.educationRequestForm', [
14729        'dekky.forms',
14730        'far.forms.partnerFromUserForm',
14731        'far.models.education.discipline',
14732        'far.models.education.userType',
14733        'far.models.education.status',
14734        'far.models.partners',
14735        'far.helpers.showModalMessage'
14736    ])
14737    .service('educationRequestForm', ["form", "educationStatus", "educationQualificationGroup", "educationDiscipline", "partners", "autocomplete", "fileUploadFilters", "partnerFromUserForm", "showModalMessage", function (form,
14738                                               educationStatus,
14739                                               educationQualificationGroup,
14740                                               educationDiscipline,
14741                                               partners,
14742                                               autocomplete,
14743                                               fileUploadFilters,
14744                                               partnerFromUserForm,
14745                                               showModalMessage) {
14746        var requestModel = form('educationRequestModel');
14747
14748        requestModel
14749            .addField('accepted', 'selectObject', {
14750                validators: {
14751                    required: true
14752                },
14753                options: {
14754                    defaultOption: 'Статус мероприятия',
14755                    class: 'form__item form__item_select width-350'
14756                },
14757                ngOptions: 'item as item.status for item in field.items track by item.id'
14758            }, educationStatus.list)
14759            .addField('homepage', 'checkbox', {
14760                validators: {
14761                    required: false
14762                },
14763                label: 'Показать на главной'
14764            })
14765            .addField('name', null, {
14766                validators: {
14767                    required: true
14768                },
14769                options: {
14770                    placeholder: 'Название мероприятия',
14771                    class: 'form__item'
14772                }
14773            })
14774            .addField('startDate', 'dateDropdowns', {
14775                validators: {
14776                    required: true
14777                }
14778            })
14779            .addField('endDate', 'dateDropdowns', {
14780                validators: {
14781                    required: true
14782                }
14783            })
14784            .addField('allYear', 'checkbox', {
14785                label: 'Круглогодично'
14786            })
14787            .addField('location', null, {
14788                validators: {
14789                    required: true
14790                }
14791            })
14792            .addField('camp', 'uiSelect', {
14793                validators: {
14794                    required: false
14795                },
14796                options: {
14797                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
14798                    class: 'form__ui-select width-600'
14799                },
14800                uiSelectOptions: {
14801                    matchTitle: '{{ $select.selected.name }} ',
14802                    choicesTitle: '{{ item.name }}',
14803                    match: {
14804                        placeholder: 'Альплагерь',
14805                        allowClear: true
14806                    },
14807                    choices: {
14808                        repeat: 'item in field.items track by item.id',
14809                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Camp", "camp")',
14810                        refreshDelay: 0
14811                    },
14812                    refreshAutoComplete: autocomplete.refreshAutoComplete
14813                }
14814            }, autocomplete.get('camp'))
14815            .addField('brief', 'textarea', {
14816                validators: {
14817                    required: true
14818                },
14819                options: {
14820                    placeholder: 'Анонс',
14821                    class: 'form__item',
14822                    maxlength: 150
14823  
14823              }
14824            })
14825            .addField('description', 'textarea', {
14826                validators: {
14827                    required: true
14828                },
14829                options: {
14830                    redactor: true,
14831                    placeholder: 'Ваше описание',
14832                    class: 'form__item'
14833                }
14834            })
14835            .addField('club', 'uiSelect', {
14836                validators: {
14837                    required: true
14838                },
14839                options: {
14840                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
14841                    class: 'form__ui-select width-600'
14842                },
14843                uiSelectOptions: {
14844                    matchTitle: '{{ $select.selected.name }} ',
14845                    choicesTitle: '{{ item.name }}',
14846                    match: {
14847                        placeholder: 'Федерация / Клуб',
14848                        allowClear: true
14849                    },
14850                    choices: {
14851                        repeat: 'item in field.items track by item.id',
14852                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Club", "club")',
14853                        refreshDelay: 0
14854                    },
14855                    refreshAutoComplete: autocomplete.refreshAutoComplete
14856                }
14857            }, autocomplete.get('club'))
14858            .addField('userChief', 'userSelect', {
14859                /*validators: {
14860                    required: true
14861                },*/
14862                options: {
14863                    class: 'form__ui-select width-450'
14864                },
14865                uiSelectOptions: {
14866                    match: {
14867                        placeholder: 'Организатор, ФИО'
14868                    },
14869                    choices: {
14870                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userChiefs")'
14871                    },
14872                    refreshAutoComplete: autocomplete.refreshAutoComplete
14873                }
14874            }, autocomplete.get('userChiefs'))
14875            .addField('userCoach', 'userSelect', {
14876                /*validators: {
14877                    required: true
14878                },*/
14879                options: {
14880                    class: 'form__ui-select width-450'
14881                },
14882                uiSelectOptions: {
14883                    match: {
14884                        placeholder: 'Старший тренер, ФИО'
14885                    },
14886                    choices: {
14887                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userCoaches")'
14888                    },
14889                    refreshAutoComplete: autocomplete.refreshAutoComplete
14890                }
14891            }, autocomplete.get('userCoaches'))
14892            .addField('userSafety', 'userSelect', {
14893                /*validators: {
14894                    required: false
14895                },*/
14896                options: {
14897                    class: 'form__ui-select width-450'
14898                },
14899                uiSelectOptions: {
14900                    match: {
14901                        placeholder: 'Ответственный за безопасность, ФИО'
14902                    },
14903                    choices: {
14904                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userSafeties")'
14905                    },
14906                    refreshAutoComplete: autocomplete.refreshAutoComplete
14907                }
14908            }, autocomplete.get('userSafeties'))
14909            .addField('participants', 'range', {
14910                validators: {
14911                    required: true
14912                },
14913                range: {
14914                    ceil: 500,
14915                    floor: 1
14916                }
14917            })
14918            .addField('partners', 'checkboxCollection', {
14919                options: {
14920                    class: 'form-group_quarter'
14921                },
14922                checkbox: {
14923                    label: 'name',
14924                    model: 'selected'
14925                }
14926            }, partners.list)
14927            .addField('localPartners', 'collection', {
14928                buttons: {
14929                    add: 'Добавить партнера',
14930                    remove: 'Удалить'
14931                }
14932            }, partnerFromUserForm)
14933            .addField('documentsFiles', 'fileUpload', {
14934                validators: {
14935                    required: true
14936                },
14937                label: 'Загрузить файл',
14938                uploader: {
14939                    url: Routing.generate('api_upload_post_file'),
14940                    autoUpload: true,
14941                    filters: [
14942                        fileUploadFilters.fileSize(),
14943                        fileUploadFilters.fileType()
14944                    ],
14945                    onSuccessItem: function (item, response) {
14946                        item.serverData = response;
14947                    },
14948                    onWhenAddingFileFailed: function (item, filter) {
14949                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
14950                        showModalMessage(message);
14951                    }
14952                }
14953            })
14954            .addField('backgroundImage', 'imageUpload', {
14955                validators: {
14956                    required: true
14957                },
14958                label: 'Загрузить фото',
14959                uploader: {
14960                    url: Routing.generate('api_upload_post_image'),
14961                    autoUpload: true,
14962                    queueLimit: 1,
14963                    onSuccessItem: function (item, response) {
14964                        item.serverData = response;
14965                    },
14966                    onAfterAddingFile: function(item) {
14967                        this.queue.length = 0;
14968                        this.queue.push(item);
14969                    },
14970                    onWhenAddingFileFailed: function (item, filter) {
14971                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
14972
14973                        if (filter.name == 'queueLimit') {
14974                            message = 'Вы можете загрузить только одно фоновое изображение';
14975                        }
14976
14977                        showModalMessage(message);
14978                    }
14979                }
14980            });
14981
14982        return requestModel;
14983    }]);
14984
14985},{"../helpers/show-modal-message/show-modal-message":167,"../models/education/educationDiscipline":201,"../models/education/educationQualificationGroup":202,"../models/education/educationStatus":204,"../models/partners/partners":222,"../modules/forms/forms":244,"./partnerFromUserForm":154}],147:[function(require,module,exports){
14986'use strict';
14987
14988require('../modules/forms/forms');
14989
14990angular.module('far.forms.eventGalleryForm', ['dekky.forms'])
14991    .service('eventGalleryForm', ["form", "fileUploadFilters", function(form, fileUploadFilters) {
14992        var eventGalleryForm = form('eventGallery');
14993
14994        eventGalleryForm
14995            .addField('slides_files', 'imageUpload', {
14996                validators: { required: true },
14997                label: 'Загрузить изображение',
14998                fieldData: {
14999                    multipleUpload: 'true'
15000                },
15001                uploader: {
15002                    url: Routing.generate('api_upload_post_image'),
15003                    filters: [
15004                        fileUploadFilters.fileSize()
15005                    ],
15006                    autoUpload: true,
15007                    removeAfterUpload: true
15008                }
15009            });
15010
15011        return eventGalleryForm;
15012    }]);
15013
15014},{"../modules/forms/forms":244}],148:[function(require,module,exports){
15015'use strict';
15016
15017require('../modules/forms/forms');
15018require('./partnerFromUserForm');
15019require('../models/discipline/discipline');
15020require('../models/event/eventStatus');
15021require('../models/partners/partners');
15022require('../helpers/show-modal-message/show-modal-message');
15023
15024angular.module('far.forms.eventProjectRequestForm', [
15025        'dekky.forms',
15026        'far.forms.partnerFromUserForm',
15027        'far.models.discipline',
15028        'far.models.event.status',
15029        'far.models.partners',
15030        'far.helpers.showModalMessage'
15031    ])
15032    .service('eventProjectRequestForm', ["form", "partnerFromUserForm", "fileUploadFilters", "Discipline", "partners", "showModalMessage", "autocomplete", "eventStatus", function (form, partnerFromUserForm, fileUploadFilters, Discipline, partners, showModalMessage, autocomplete, eventStatus) {
15033        var eventProjectRequestForm = form('eventProjectRequestForm');
15034
15035        eventProjectRequestForm
15036            .addField('accepted', 'selectObject', {
15037                validators: {
15038                    required: true
15039                },
15040                options: {
15041                    defaultOption: 'Статус проекта',
15042                    class: 'form__item form__item_select width-350'
15043                },
15044                ngOptions: 'item as item.status for item in field.items track by item.id'
15045            }, eventStatus.list)
15046            .addField('homepage', 'checkbox', {
15047                validators: {
15048                    required: false
15049                },
15050                label: 'Показать на главной'
15051            })
15052            .addField('main_banner', 'checkbox', {
15053                validators: {
15054                    required: false
15055                },
15056                label: 'Баннер на главной'
15057            })
15058            .addField('disciplines', 'selectObject', {
15059                validators: {
15060                    required: true
15061                },
15062                options: {
15063                    defaultOption: 'Дисциплина',
15064                    class: 'form__item form__item_select width-350',
15065                    ngChange: 'field.ngChange(model)'
15066                },
15067                ngOptions: 'item as item.name for item in field.items track by item.id'
15068            }, Discipline.list)
15069            .addField('date_from', 'dateDropdowns', {
15070                validators: {
15071                    required: true
15072                }
15073            })
15074            .addField('date_to', 'dateDropdowns', {
15075                validators: {
15076                    required: true
15077                }
15078            })
15079            .addField('participants', 'range', {
15080                validators: {
15081                    required: true
15082                },
15083                range: {
15084                    ceil: 500,
15085                    floor: 1
15086                }
15087            })
15088            .addField('location', null, {
15089                validators: {
15090                    required: true
15091                }
15092            })
15093            .addField('camp', 'uiSelect', {
15094                validators: {
15095                    required: false
15096                },
15097                options: {
15098                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
15099                    class: 'form__ui-select width-600'
15100                },
15101                uiSelectOptions: {
15102                    matchTitle: '{{ $select.selected.name }} ',
15103                    choicesTitle: '{{ item.name }}',
15104                    match: {
15105                        placeholder: 'Альплагерь',
15106                        allowClear: true
15107                    },
15108                    choices: {
15109                        repeat: 'item in field.items track by item.id',
15110                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Camp", "camp")',
15111                        refreshDelay: 0
15112                    },
15113                    refreshAutoComplete: autocomplete.refreshAutoComplete
15114                }
15115            }, autocomplete.get('camp'))
15116            .addField('name', null, {
15117                validators: {
15118                    required: true
15119                },
15120                options: {
15121                    placeholder: 'Название проекта',
15122                    class: 'form__item'
15123                }
15124            })
15125            .addField('brief', 'textarea', {
15126                validators: {
15127                    required: true
15128                },
15129                options: {
15130                    placeholder: 'Анонс',
15131                    class: 'form__item',
15132                    maxlength: 150
15133                }
15134            })
15135            .addField('description', 'textarea', {
15136                validators: {
15137                    required: true
15138                },
15139                options: {
15140                    redactor: true,
15141                    placeholder: 'Ваше описание',
15142                    class: 'form__item'
15143                }
15144            })
15145            .addField('club', 'uiSelect', {
15146                validators: {
15147                    required: true
15148                },
15149                options: {
15150                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
15151                    class: 'form__ui-select'
15152                },
15153                uiSelectOptions: {
15154                    matchTitle: '{{ $select.selected.name }} ',
15155                    choicesTitle: '{{ item.name }}',
15156                    match: {
15157                        placeholder: 'Федерация / Клуб',
15158                        allowClear: true
15159                    },
15160                    choices: {
15161                        repeat: 'item in field.items track by item.id',
15162                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Club", "club")',
15163                        refreshDelay: 0
15164                    },
15165                    refreshAutoComplete: autocomplete.refreshAutoComplete
15166                }
15167            }, autocomplete.get('club'))
15168            .addField('user_director', 'userSelect', {
15169                validators: {
15170                    required: true
15171                },
15172                options: {
15173                    class: 'form__ui-select'
15174                },
15175                uiSelectOptions: {
15176                    match: {
15177                        placeholder: 'Директор, ФИО'
15178                    },
15179                    choices: {
15180                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "user_director")'
15181                    },
15182                    refreshAutoComplete: autocomplete.refreshAutoComplete
15183                }
15184            }, autocomplete.get('user_director'))
15185            .addField('user_main_judge', 'userSelect', {
15186                validators: {
15187                    required: true
15188                },
15189                options: {
15190                    class: 'form__ui-select'
15191                },
15192                uiSelectOptions: {
15193                    match: {
15194                        placeholder: 'Главный судья, ФИО'
15195                    },
15196                    choices: {
15197                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "user_main_judge")'
15198                    },
15199                    refreshAutoComplete: autocomplete.refreshAutoComplete
15200                }
15201            }, autocomplete.get('user_main_judge'))
15202            .addField('partners', 'checkboxCollection', {
15203                options: {
15204                    class: 'form-group_quarter'
15205                },
15206                checkbox: {
15207                    label: 'name',
15208                    model: 'selected'
15209                }
15210            }, partners.list)
15211            .addField('documentsFiles', 'fileUpload', {
15212                validators: {
15213                    required: true
15214                },
15215                label: 'Загрузить файл',
15216                uploader: {
15217                    url: Routing.generate('api_upload_post_file'),
15218                    autoUpload: true,
15219                    filters: [
15220                        fileUploadFilters.fileSize(),
15221                        fileUploadFilters.fileType()
15222                    ],
15223                    onSuccessItem: function (item, response) {
15224                        item.serverData = response;
15225                    },
15226                    onWhenAddingFileFailed: function (item, filter) {
15227                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
15228      
15228                  showModalMessage(message);
15229                    }
15230                }
15231            })
15232            .addField('backgroundImage', 'imageUpload', {
15233                validators: {
15234                    required: true
15235                },
15236                label: 'Загрузить фото',
15237                uploader: {
15238                    url: Routing.generate('api_upload_post_image'),
15239                    autoUpload: true,
15240                    queueLimit: 1,
15241                    onSuccessItem: function (item, response) {
15242                        item.serverData = response;
15243                    },
15244                    onWhenAddingFileFailed: function (item, filter) {
15245                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
15246
15247                        if (filter.name == 'queueLimit') {
15248                            message = 'Вы можете загрузить только одно фоновое изображение';
15249                        }
15250
15251                        showModalMessage(message);
15252                    }
15253                }
15254            });
15255
15256        return eventProjectRequestForm;
15257    }]);
15258
15259},{"../helpers/show-modal-message/show-modal-message":167,"../models/discipline/discipline":196,"../models/event/eventStatus":210,"../models/partners/partners":222,"../modules/forms/forms":244,"./partnerFromUserForm":154}],149:[function(require,module,exports){
15260'use strict';
15261
15262require('../models/ascent/ascentTypes');
15263require('../helpers/show-modal-message/show-modal-message');
15264
15265angular.module('far.forms.eventReportForm', [
15266    'dekky.forms',
15267    'far.models.ascentTypes',
15268    'far.helpers.showModalMessage'
15269])
15270.service('eventReportForm', ["form", "autocomplete", "ascentTypes", "fileUploadFilters", "showModalMessage", function(
15271    form,
15272    autocomplete,
15273    ascentTypes,
15274    fileUploadFilters,
15275    showModalMessage
15276) {
15277    var reportModel = form('eventReportModel');
15278    var ascentModel = form('ascentModel');
15279    var userModel = form('userModel');
15280
15281    userModel
15282        .addField('fio', 'uiTypeahead', {
15283            validators: {
15284                required: true
15285            },
15286            options: {
15287                placeholder: 'Участник',
15288                class: 'form__item width-350 margin_r_20',
15289                uibTypeahead: "row for row in field.refreshAutoComplete($viewValue, 'Users')",
15290                typeaheadOnSelect: 'field.userSelect($item, $model, $label, $event, fieldData)',
15291                typeaheadTemplateUrl: '/dekky.forms/themes/typeaheadUser/typeahead-match.html',
15292                typeaheadInputFormatter: 'field.formatLabel($model)'
15293            },
15294            fieldData: {
15295                clearBtn: true,
15296                refreshAutoComplete: function(name, term) {
15297                    return autocomplete.refreshAutoComplete(name, term);
15298                },
15299                userSelect: function($item, $model, $label, $event, parentItem) {
15300                    parentItem.email = $item.email;
15301                },
15302                formatLabel: function($model) {
15303                    if (angular.isObject($model)) {
15304                        return $model.fio;
15305                    } else {
15306                        return $model;
15307                    }
15308                }
15309            }
15310        }, autocomplete.get('ascentUsers'))
15311        .addField('email', null, {
15312            validators: {
15313                required: false
15314            },
15315            options: {
15316                class: 'form__item width-350',
15317                placeholder: 'E-mail участника'
15318            }
15319        });
15320
15321    ascentModel
15322        .addField('ascent_date', 'dateDropdowns', {
15323            validators: { required: true }
15324        })
15325        .addField('ascent_mountain_peak', 'mountainPeakSelect', {
15326            options: {
15327                class: 'form__ui-select width-350'
15328            }
15329        })
15330        .addField('ascent_mountain_route', 'selectObject', {
15331            validators: {
15332                required: true
15333            },
15334            options: {
15335                defaultOption: 'Маршрут',
15336                onSelect: 'field.uiSelectOptions.onSelect($item)',
15337                class: 'form__item form__item_select width-350 margin_r_20'
15338            },
15339            ngOptions: 'item as item.name + " / " +item.mountain_route_complexity.name  for item in field.items track by item.id'
15340        }, [])
15341        .addField('ascent_type', 'selectObject', {
15342            validators: { required: false },
15343            options: {
15344                defaultOption: 'Способ восхождения',
15345                class: 'form__item width-350 margin_r_20 form__item_select'
15346            },
15347            ngOptions: 'item as item.name for item in field.items track by item.id'
15348        }, ascentTypes.list)
15349        .addField('instructor', 'userSelect', {
15350            validators: { required: false },
15351            options: {
15352                class: 'form__ui-select width-350 margin_b_20'
15353            },
15354            uiSelectOptions: {
15355                match: {
15356                    placeholder: 'Инструктор'
15357                },
15358                choices: {
15359                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "instructor")'
15360                },
15361                refreshAutoComplete: autocomplete.refreshAutoComplete
15362            }
15363        }, autocomplete.get('instructor'))
15364        .addField('user_chief', 'userSelect', {
15365            validators: { required: false },
15366            options: {
15367                class: 'form__ui-select width-350 margin_b_20'
15368            },
15369            uiSelectOptions: {
15370                match: {
15371                    placeholder: 'Руководитель'
15372                },
15373                choices: {
15374                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userСhief")'
15375                },
15376                refreshAutoComplete: autocomplete.refreshAutoComplete
15377            }
15378        }, autocomplete.get('userСhief'))
15379        .addField('ascent_users', 'collection', {
15380            buttons: {
15381                add: 'Добавить участника',
15382                remove: 'Удалить'
15383            }
15384        }, userModel);
15385
15386    reportModel
15387        .addField('userInstructor', 'userSelect', {
15388            uiSelectOptions: {
15389                choices: {
15390                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userInstructor")'
15391                },
15392                refreshAutoComplete: autocomplete.refreshAutoComplete
15393            }
15394        }, autocomplete.get('userInstructor'))
15395        .addField('userJuniorInstructor', 'userSelect', {
15396            uiSelectOptions: {
15397                choices: {
15398                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userJuniorInstructor")'
15399                },
15400                refreshAutoComplete: autocomplete.refreshAutoComplete
15401            }
15402        }, autocomplete.get('userJuniorInstructor'))
15403        .addField('countUsersTotal', null, {
15404            'validators': {
15405                required: false,
15406                numericOnly: ''
15407            }
15408        })
15409        .addField('countUsersCc', null, {
15410            'validators': {
15411                required: false,
15412                numericOnly: ''
15413            }
15414        })
15415        .addField('countUsersCp', null, {
15416            'validators': {
15417                required: false,
15418                numericOnly: ''
15419            }
15420        })
15421        .addField('countUsersNp', null, {
15422            'validators': {
15423                required: false,
15424                numericOnly: ''
15425            }
15426        })
15427        .addField('countUsersCm', null, {
15428            'validators': {
15429                required: false,
15430                numericOnly: ''
15431            }
15432        })
15433        .addField('documentsFiles', 'fileUpload', {
15434            validators: {
15435                required: true
15436            },
15437            label: 'Загрузить файл',
15438            uploader: {
15439                url: Routing.generate('api_upload_post_file'),
15440                autoUpload: true,
15441                filters: [
15442                    fileUploadFilters.fileSize(),
15443                    fileUploadFilters.fileType()
15444                ],
15445                onSuccessItem: function (item, response) {
15446                    item.serverData = response;
15447                },
15448                onWhenAddingFileFailed: function(item, filter) {
15449                    var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
15450                    showModalMessage(message);
15451                }
15452            }
15453        })
15454        .addField('ascents', 'collection', {
15455            validators: {
15456                required: false,
15457                collectionMinlength: 0
15458            },
15459            buttons: {
15460                add: 'Добавить восхождение',
15461                remove: 'Удалить восхождение',
15462                copy: 'Копировать восхождение',
15463                save: 'Сохранить'
15464            }
15465        }, ascentModel);
15466
15467    return reportModel;
15468}]);
15469
15470},{"../helpers/show-modal-message/show-modal-message":167,"../models/ascent/ascentTypes":183}],150:[function(require,module,exports){
15471'use strict';
15472
15473require('../modules/forms/forms');
15474require('../models/event/eventDiscipline');
15475require('../models/event/eventStatus');
15476require('../models/event/eventRegions');
15477require('../models/event/eventQualificationGroup');
15478require('../models/partners/partners');
15479require('./partnerFromUserForm');
15480require('../helpers/show-modal-message/show-modal-message');
15481
15482angular.module('far.forms.eventRequestForm', [
15483        'dekky.forms',
15484        'far.forms.partnerFromUserForm',
15485        'far.models.event.discipline',
15486        'far.models.event.userType',
15487        'far.models.event.status',
15488         'far.models.event.regions',
15489        'far.models.partners',
15490        'far.helpers.showModalMessage'
15491    ])
15492    .service('eventRequestForm', ["form", "eventStatus", "eventQualificationGroup", "eventDiscipline", "eventRegions", "partners", "autocomplete", "fileUploadFilters", "partnerFromUserForm", "showModalMessage", function (form,
15493                                           eventStatus,
15494                                           eventQualificationGroup,
15495                                           eventDiscipline,
15496                                           eventRegions,
15497                                           partners,
15498                                           autocomplete,
15499                                           fileUploadFilters,
15500                                           partnerFromUserForm,
15501                                           showModalMessage) {
15502      
15503        var requestModel = form('eventRequestModel');
15504        
15505
15506        requestModel
15507            .addField('accepted', 'selectObject', {
15508                validators: {
15509                    required: true
15510                },
15511                options: {
15512                    defaultOption: 'Статус мероприятия',
15513                    class: 'form__item form__item_select width-350'
15514                },
15515                ngOptions: 'item as item.status for item in field.items track by item.id'
15516            }, eventStatus.list)
15517            .addField('name', null, {
15518                validators: {
15519                    required: true
15520                },
15521                options: {
15522                    placeholder: 'Название мероприятия',
15523                    class: 'form__item'
15524                }
15525            })
15526            .addField('startDate', 'dateDropdowns')
15527            .addField('endDate', 'dateDropdowns')
15528            .addField('allYear', 'checkbox', {
15529                label: 'Круглогодично'
15530            })
15531            .addField('location', null, {
15532                validators: {
15533                    required: true
15534                }
15535            })
15536            .addField('camp', 'uiSelect', {
15537                validators: {
15538                    required: false
15539                },
15540                options: {
15541                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
15542                    class: 'form__ui-select width-600'
15543                },
15544                uiSelectOptions: {
15545                    matchTitle: '{{ $select.selected.name }} ',
15546                    choicesTitle: '{{ item.name }}',
15547                    match: {
15548                        placeholder: 'Альплагерь',
15549                        allowClear: true
15550                    },
15551                    choices: {
15552                        repeat: 'item in field.items track by item.id',
15553                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Camp", "camp")',
15554                        refreshDelay: 0
15555                    },
15556                    refreshAutoComplete: autocomplete.refreshAutoComplete
15557                }
15558            }, autocomplete.get('camp'))
15559            .addField('brief', 'textarea', {
15560                validators: {
15561                    required: true
15562                },
15563                options: {
15564                    placeholder: 'Анонс',
15565                    class: 'form__item',
15566                    maxlength: 150
15567                }
15568            })
15569            .addField('description', 'textarea', {
15570                validators: {
15571                    required: true
15572                },
15573                options: {
15574                    redactor: true,
15575                    placeholder: 'Ваше описание',
15576                    class: 'form__item'
15577                }
15578            })
15579            .addField('club', 'uiSelect', {
15580                validators: {
15581                    required: true
15582                },
15583                options: {
15584                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
15585                    class: 'form__ui-select width-600'
15586                },
15587                uiSelectOptions: {
15588                    matchTitle: '{{ $select.selected.name }} ',
15589                    choicesTitle: '{{ item.name }}',
15590                    match: {
15591                        placeholder: 'Федерация / Клуб',
15592                        allowClear: true
15593                    },
15594                    choices: {
15595                        repeat: 'item in field.items track by item.id',
15596                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Club", "club")',
15597                        refreshDelay: 0
15598                    },
15599                    refreshAutoComplete: autocomplete.refreshAutoComplete
15600                }
15601            }, autocomplete.get('club'))
15602            .addField('userChief', 'userSelect', {
15603                validators: {
15604                    required: true
15605                },
15606                options: {
15607                    class: 'form__ui-select width-450'
15608                },
15609                uiSelectOptions: {
15610                    match: {
15611                        placeholder: 'Организатор, ФИО'
15612                    },
15613                    choices: {
15614                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userChiefs")'
15615                    },
15616                    refreshAutoComplete: autocomplete.refreshAutoComplete
15617                }
15618            }, autocomplete.get('userChiefs'))
15619            .addField('userCoach', 'userSelect', {
15620                validators: {
15621                    required: true
15622                },
15623                options: {
15624                    class: 'form__ui-select width-450'
15625                },
15626                uiSelectOptions: {
15627                    match: {
15628                        placeholder: 'Старший тренер, ФИО'
15629                    },
15630                    choices: {
15631                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userCoaches", {userType: "coach"})'
15632                    },
15633                    refreshAutoComplete: autocomplete.refreshAutoComplete
15634                }
15635            }, autocomplete.get('userCoaches'))
15636            .addField('userSafety', 'userSelect', {
15637                validators: {
15638                    required: true
15639                },
15640                options: {
15641                    class: 'form__ui-select width-450'
15642                },
15643                uiSelectOptions: {
15644    
15644                match: {
15645                        placeholder: 'Ответственный за безопасность, ФИО'
15646                    },
15647                    choices: {
15648                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "userSafeties", {userType: "safety"})'
15649                    },
15650                    refreshAutoComplete: autocomplete.refreshAutoComplete
15651                }
15652            }, autocomplete.get('userSafeties'))
15653            
15654            .addField('participants', 'range', {
15655                validators: {
15656                    required: true
15657                },
15658                range: {
15659                    ceil: 500,
15660                    floor: 1
15661                }
15662            })
15663
15664            .addField('revisor', 'selectObject', {
15665                validators: {
15666                    required: true
15667                },
15668                options: {
15669                    defaultOption: 'Регион',
15670                    class: 'form__item form__item_select width-350'
15671                },
15672                ngOptions: 'item as item.region for item in field.items track by item.id'
15673            },eventRegions.list)
15674            
15675           
15676           
15677            .addField('participants', 'range', {
15678                validators: {
15679                    required: true
15680                },
15681                range: {
15682                    ceil: 500,
15683                    floor: 1
15684                }
15685            })
15686            
15687            .addField('partners', 'checkboxCollection', {
15688                options: {
15689                    class: 'form-group_quarter'
15690                },
15691                checkbox: {
15692                    label: 'name',
15693                    model: 'selected'
15694                }
15695            }, partners.list)
15696            .addField('localPartners', 'collection', {
15697                buttons: {
15698                    add: 'Добавить партнера',
15699                    remove: 'Удалить'
15700                }
15701            }, partnerFromUserForm)
15702            .addField('documentsFiles', 'fileUpload', {
15703                validators: {
15704                    required: true
15705                },
15706                label: 'Загрузить файл',
15707                uploader: {
15708                    url: Routing.generate('api_upload_post_file'),
15709                    autoUpload: true,
15710                    filters: [
15711                        fileUploadFilters.fileSize(),
15712                        fileUploadFilters.fileType()
15713                    ],
15714                    onSuccessItem: function (item, response) {
15715                        item.serverData = response;
15716                    },
15717                    onWhenAddingFileFailed: function (item, filter) {
15718                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
15719                        showModalMessage(message);
15720                    }
15721                }
15722            })
15723            .addField('backgroundImage', 'imageUpload', {
15724                validators: {
15725                    required: true
15726                },
15727                label: 'Загрузить фото',
15728                uploader: {
15729                    url: Routing.generate('api_upload_post_image'),
15730                    autoUpload: true,
15731                    queueLimit: 1,
15732                    onSuccessItem: function (item, response) {
15733                        item.serverData = response;
15734                    },
15735                    onAfterAddingFile: function(item) {
15736                        this.queue.length = 0;
15737                        this.queue.push(item);
15738                    },
15739                    onWhenAddingFileFailed: function (item, filter) {
15740                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
15741
15742                        if (filter.name == 'queueLimit') {
15743                            message = 'Вы можете загрузить только одно фоновое изображение';
15744                        }
15745
15746                        showModalMessage(message);
15747                    }
15748                }
15749            });
15750
15751        return requestModel;
15752    }]);
15753
15754},{"../helpers/show-modal-message/show-modal-message":167,"../models/event/eventDiscipline":206,"../models/event/eventQualificationGroup":207,"../models/event/eventRegions":208,"../models/event/eventStatus":210,"../models/partners/partners":222,"../modules/forms/forms":244,"./partnerFromUserForm":154}],151:[function(require,module,exports){
15755'use strict';
15756
15757require('../modules/forms/forms');
15758
15759angular.module('far.forms.inviteUserForm', ['dekky.forms'])
15760.service('inviteUserForm', ["form", function(form) {
15761	var userInvite = form('userInvite');
15762
15763	userInvite
15764		.addField('members_invite_email', 'text', {
15765			validators: {
15766				required: true
15767			},
15768			options: {
15769				placeholder: 'E-mail',
15770				uniqueUser: '',
15771				class: 'form__item width-184 margin_r_20'
15772			}
15773		})
15774		.addField('members_invite_last_name', 'text', {
15775			validators: {
15776				required: true
15777			},
15778			options: {
15779				placeholder: 'Фамилия',
15780				class: 'form__item width-184 margin_r_20'
15781			}
15782		})
15783		.addField('members_invite_first_name', 'text', {
15784			validators: {
15785				required: true
15786			},
15787			options: {
15788				placeholder: 'Имя',
15789				class: 'form__item width-184'
15790			}
15791		});
15792
15793	return userInvite;
15794}]);
15795
15796},{"../modules/forms/forms":244}],152:[function(require,module,exports){
15797'use strict';
15798
15799require('../modules/forms/forms');
15800require('../models/mountains/routeTypes');
15801require('../models/mountains/routeComplexities');
15802require('../helpers/show-modal-message/show-modal-message');
15803
15804angular.module('far.forms.mountainRouteForm', [
15805	'dekky.forms',
15806	'far.models.mountains.routeTypes',
15807	'far.models.mountains.routeComplexities',
15808	'far.helpers.showModalMessage'
15809])
15810.service('mountainRouteForm', ["form", "autocomplete", "mountainRouteTypes", "mountainRouteComplexities", "fileUploadFilters", "showModalMessage", function(form, autocomplete, mountainRouteTypes, mountainRouteComplexities, fileUploadFilters, showModalMessage) {
15811	var mountainRouteModel = form('mountainRouteModel');
15812
15813	mountainRouteModel
15814		.addField('name', null, {
15815			validators: { required: true },
15816			options: { placeholder: 'Название' }
15817		})
15818		.addField('description', 'textarea', {
15819			options: {
15820                redactor: true,
15821				placeholder: 'Ваше описание'
15822			}
15823		})
15824		.addField('num', null, {
15825			options: { placeholder: 'Номер' }
15826		})
15827		.addField('route_status', 'checkbox')
15828		.addField('slides', 'hidden')
15829		.addField('documents', 'hidden')
15830		.addField('first_ascent_year', null, {
15831			validators: { required: false },
15832			options: { placeholder: 'Год прохождения', maxlength: 4, numericOnly: '' }
15833		})
15834        .addField('camp', 'uiSelect', {
15835            validators: {
15836                required: false
15837            },
15838            options: {
15839                onSelect: 'field.uiSelectOptions.onSelect($item, $model)'
15840            },
15841            uiSelectOptions: {
15842                matchTitle: '{{ $select.selected.name }} ',
15843                choicesTitle: '{{ item.name }}',
15844                match: {
15845                    placeholder: 'Альплагерь',
15846                    allowClear: true
15847                },
15848                choices: {
15849                    repeat: 'item in field.items track by item.id',
15850                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Camp", "camp")',
15851                    refreshDelay: 0
15852                },
15853                refreshAutoComplete: autocomplete.refreshAutoComplete
15854            }
15855        }, autocomplete.get('camp'))
15856
15857		.addField('mountain_peak', 'mountainPeakSelect')
15858
15859		.addField('routeType', 'selectObject', {
15860			validators: { required: true },
15861			ngOptions: 'item as item.name for item in field.items track by item.id',
15862			label_before: 'Характер маршрута:',
15863			label_before_class: 'form__comment'
15864		}, mountainRouteTypes.list)
15865		.addField('routeComplexity', 'selectObject', {
15866			validators: { required: true },
15867			ngOptions: 'item as item.name for item in field.items track by item.id',
15868			label_before: 'Категория сложности:',
15869			label_before_class: 'form__comment'
15870		}, mountainRouteComplexities.list)
15871        .addField('routeUser', 'userSelect', {
15872          
15873            uiSelectOptions: {
15874                match: {
15875                    placeholder: 'Имя и фамилия руководителя'
15876                },
15877                choices: {
15878                    refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "users")'
15879                },
15880                refreshAutoComplete: autocomplete.refreshAutoComplete
15881            }
15882        }, autocomplete.get('users'))
15883        .addField('newRouteUserFirstName', null, {
15884			options: {placeholder: 'Имя  руководителя'},
15885		})
15886		.addField('newRouteUserLastName', null, {
15887			options: {placeholder: 'Фaмилия руководителя'},
15888		})
15889		.addField('slidesFiles', 'imageUpload', {
15890			validators: { required: true },
15891			label: 'Загрузить изображение',
15892			uploader: {
15893				url: Routing.generate('api_upload_post_image'),
15894				filters: [
15895					fileUploadFilters.fileSize()
15896				],
15897				autoUpload: true,
15898				removeAfterUpload: true,
15899				onWhenAddingFileFailed: function(item, filter) {
15900					var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
15901					showModalMessage(message);
15902				}
15903			}
15904		})
15905		.addField('documentsFiles', 'fileUpload', {
15906			validators: { required: true },
15907			label: 'Загрузить документ',
15908			uploader: {
15909				url: Routing.generate('api_upload_post_file'),
15910				autoUpload: true,
15911				filters: [
15912					fileUploadFilters.fileSize(),
15913					fileUploadFilters.fileType()
15914				],
15915				// onSuccessItem: function (item, response) {
15916				// 	item.serverData = response;
15917				// },
15918				onWhenAddingFileFailed: function(item, filter) {
15919					var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
15920					showModalMessage(message);
15921				}
15922			}
15923		});
15924
15925	return mountainRouteModel;
15926}]);
15927
15928},{"../helpers/show-modal-message/show-modal-message":167,"../models/mountains/routeComplexities":215,"../models/mountains/routeTypes":216,"../modules/forms/forms":244}],153:[function(require,module,exports){
15929'use strict';
15930
15931require('../modules/forms/forms');
15932
15933angular.module('far.forms.newsForm', ['dekky.forms'])
15934    .service('newsForm', ["form", "fileUploadFilters", "showModalMessage", "NewsCategory", "Committee", "Discipline", function (form, fileUploadFilters, showModalMessage, NewsCategory, Committee, Discipline) {
15935        var newsForm = form('news');
15936
15937        var errorMessages = [];
15938
15939        newsForm
15940            .addField('disable_comments', 'checkbox', {
15941                validators: {
15942                    required: false
15943                },
15944                label: 'Отключить комментарии'
15945            })
15946            .addField('meta_title', 'text', {
15947                validators: {
15948                    required: false
15949                },
15950                options: {
15951                    placeholder: 'Meta title'
15952                }
15953            })
15954            .addField('meta_description', 'text', {
15955                validators: {
15956                    required: false
15957                },
15958                options: {
15959                    placeholder: 'Meta description'
15960                }
15961            })
15962            .addField('top', 'checkbox', {
15963                validators: {
15964                    required: false
15965                },
15966                label: 'TOP Новость'
15967            })
15968            .addField('homepage', 'checkbox', {
15969                validators: {
15970                    required: false
15971                },
15972                label: 'На главную'
15973            })
15974            .addField('accident', 'checkbox', {
15975                validators: {
15976                    required: false
15977                },
15978                label: 'Несчастный случай'
15979            })
15980            .addField('name', 'text', {
15981                validators: {
15982                    required: true
15983                },
15984                options: {
15985                    placeholder: 'Название новости'
15986                }
15987            })
15988            .addField('header', 'text', {
15989                validators: {
15990                    required: true
15991                },
15992                options: {
15993                    placeholder: 'Заголовок новости'
15994                }
15995            })
15996            .addField('committees', 'checkboxCollection', {
15997                checkbox: {
15998                    label: 'name',
15999                    model: 'selected'
16000                }},
16001            Committee.list)
16002            .addField('disciplines', 'checkboxCollection', {
16003                checkbox: {
16004                    label: 'name',
16005                    model: 'selected'
16006                }
16007            },Discipline.list)
16008            .addField('categories', 'checkboxCollection', {
16009                checkbox: {
16010                    label: 'name',
16011                    model: 'selected'
16012                }
16013            }, NewsCategory.list)
16014            .addField('created', 'dateDropdowns', {
16015                validators: {
16016                    required: false
16017                },
16018                options: {
16019                    placeholder: 'Дата публикации'
16020                }
16021            })
16022            .addField('brief', 'text', {
16023                validators: {
16024                    required: false
16025                },
16026                options: {
16027                    placeholder: 'Небольшой анонс',
16028                    maxlength: 140
16029                }
16030            })
16031            .addField('content', 'textarea', {
16032                validators: {
16033                    required: false
16034                },
16035                options: {
16036                    redactor: true,
16037                    placeholder: 'Основной текст'
16038                }
16039            })
16040            .addField('source', 'text', {
16041                validators: {
16042                    required: false
16043                },
16044                options: {
16045                    placeholder: 'Источник'
16046                }
16047            })
16048            .addField('youtube', 'text', {
16049                validators: {
16050                    required: false
16051                },
16052                options: {
16053                    placeholder: 'Youtube (ссылка)'
16054                }
16055            })
16056            .addField('avatar', 'imageUpload', {
16057                validators: {
16058                    required: false
16059                },
16060                uploader: {
16061                    url: Routing.generate('api_upload_post_avatar'),
16062                    autoUpload: true,
16063                    removeAfterUpload: true,
16064                    filters: [
16065                        fileUploadFilters.fileSize()
16066                    ],
16067                    onWhenAddingFileFailed: function (item, filter) {
16068                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
16069                        showModalMessage(message);
16070                    }
16071                }
16072            })
16073            .addField('slides_files', 'imageUpload', {
16074                validators: {
16075                    required: true
16076                },
16077                fieldData: {
16078                    multipleUpload: 'true'
16079                },
16080                label: 'Загрузить изображение',
16081                uploader: {
16082                    url: Routing.generate('api_upload_post_image'),
16083                    filters: [
16084                        fileUploadFilters.fileSize()
16085                    ],
16086                    autoUpload: true,
16087                    removeAfterUpload: true,
16088                    onWhenAddingFileFailed: function (item, filter) {
16089                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
16090
16091                        if (errorMessages.indexOf(message) == -1) {
16092                            errorMessages.push(message);
16093                        }
16094                    },
16095                    onErrorItem: function () {
16096                        var message = 'Невозможно загрузить файл на сервер';
16097
16098                        if (errorMessages.indexOf(message) == -1) {
16099                            errorMessages.push(message);
16100                        }
16101                    },
16102                    onCompleteAll: function () {
16103                        if (errorMessages.length > 0) {
16104                            showModalMessage(errorMessages.slice(0), 'Некоторые файлы не были загружены, т.к.:');
16105                            errorMessages = [];
16106                        }
16107                    }
16108                }
16109            })
16110            ;
16111
16112        return newsForm;
16113    }]);
16114
16115},{"../modules/forms/forms":244}],154:[function(require,module,exports){
16116'use strict';
16117
16118require('../modules/forms/forms');
16119require('./themes/customPartner/customPartner');
16120require('../helpers/show-modal-message/show-modal-message');
16121
16122angular.module('far.forms.partnerFromUserForm', ['dekky.forms', 'dekky.forms.themes.customPartner', 'far.helpers.showModalMessage'])
16123.service('partnerFromUserForm', ["form", "showModalMessage", function(form, showModalMessage) {
16124	var customPartnerModel = form('partnerFromUserForm', {
16125		theme: '/dekky.forms/themes/customPartner'
16126	});
16127
16128	customPartnerModel
16129		.addField('name', null, {
16130			validators: {
16131				required: true
16132			},
16133			options: {
16134				placeholder: 'Название',
16135				class: 'form__item width-250'
16136			}
16137		})
16138		.addField('url', 'url', {
16139			validators: {
16140				required: true
16141			},
16142			options: {
16143				placeholder: 'Ссылка',
16144				class: 'form__item width-250'
16145			}
16146		})
16147		.addField('logo', 'imageUpload', {
16148			validators: {
16149				required: true
16150			},
16151			label: 'Загрузить логотип',
16152			uploader: {
16153				url: Routing.generate('api_upload_post_image'),
16154				autoUpload: true,
16155				personalUploader: true,
16156				onAfterAddingFile: function(item) {
16157					this.queue.length = 0;
16158					this.queue.push(item);
16159				},
16160				onSuccessItem: function (item, response) {
16161					item.serverData = response;
16162				}
16163			}
16164		});
16165
16166	return customPartnerModel;
16167}]);
16168
16169},{"../helpers/show-modal-message/show-modal-message":167,"../modules/forms/forms":244,"./themes/customPartner/customPartner":157}],155:[function(require,module,exports){
16170'use strict';
16171
16172require('../modules/forms/forms');
16173require('../models/discipline/discipline');
16174require('../helpers/show-modal-message/show-modal-message');
16175
16176angular.module('far.forms.projectReportForm', [
16177        'dekky.forms',
16178        'far.models.discipline',
16179        'far.helpers.showModalMessage'
16180    ])
16181    .service('projectReportForm', ["form", "fileUploadFilters", "showModalMessage", "autocomplete", function (form, fileUploadFilters, showModalMessage, autocomplete) {
16182        var projectReportForm = form('projectReportForm');
16183
16184        projectReportForm
16185            .addField('users', 'userSelect', {
16186                uiSelectOptions: {
16187                    choices: {
16188                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Users", "user")'
16189                    },
16190                    refreshAutoComplete: autocomplete.refreshAutoComplete
16191                }
16192            }, autocomplete.get('user'))
16193            .addField('documentsFiles', 'fileUpload', {
16194                validators: {
16195                    required: false
16196                },
16197                label: 'Загрузить файл',
16198                uploader: {
16199                    url: Routing.generate('api_upload_post_file'),
16200                    autoUpload: true,
16201                    filters: [
16202                        fileUploadFilters.fileSize(),
16203                        fileUploadFilters.fileType()
16204                    ],
16205                    onSuccessItem: function (item, response) {
16206                        item.serverData = response;
16207                    },
16208                    onWhenAddingFileFailed: function (item, filter) {
16209                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
16210                        showModalMessage(message);
16211                    }
16212                }
16213            });
16214
16215        return projectReportForm;
16216    }]);
16217
16218},{"../helpers/show-modal-message/show-modal-message":167,"../models/discipline/discipline":196,"../modules/forms/forms":244}],156:[function(require,module,exports){
16219/**
16220 * Created by PhpStorm on 08.05.2017.
16221 * Author: Shabalin Pavel
16222 * Email: [email protected]
16223 */
16224'use strict';
16225
16226require('../modules/forms/forms');
16227require('../helpers/show-modal-message/show-modal-message');
16228
16229angular.module('far.forms.subclubEditForm', ['dekky.forms', 'far.helpers.showModalMessage'])
16230    .service('subclubEditForm', ["form", "autocomplete", "showModalMessage", function(form, autocomplete, showModalMessage) {
16231
16232        var subclubForm = form('sub-club');
16233
16234        subclubForm.autoCompleteSelect = {
16235            country: null,
16236            region: null,
16237            city: null,
16238            organization: null
16239        };
16240
16241        subclubForm
16242            .addField('name', 'text', {
16243                validators: {
16244                    required: true
16245                },
16246                options: {
16247                    placeholder: 'Название клуба'
16248                }
16249            })
16250            .addField('club', 'uiSelect', {
16251                validators: {
16252                    required: false
16253                },
16254                options: {
16255                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
16256                    class: 'form__ui-select width-650'
16257                },
16258                uiSelectOptions: {
16259                    matchTitle: '{{ $select.selected.name }} ',
16260                    choicesTitle: '{{ item.name }}',
16261                    match: {
16262                        placeholder: 'Федерация альпинизма',
16263                        allowClear: true
16264                    },
16265                    choices: {
16266                        repeat: 'item in field.items track by item.id',
16267                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Club", "club")',
16268                        refreshDelay: 0
16269                    },
16270                    refreshAutoComplete: autocomplete.refreshAutoComplete,
16271                    onSelect: function( item ) {
16272                        if ( item ) {
16273                            subclubForm.autoCompleteSelect.organization = item.id;
16274                        }
16275                    }
16276                }
16277            }, autocomplete.get('club'))
16278            .addField('country', 'uiSelect', {
16279                validators: {
16280                    required: false
16281                },
16282                options: {
16283                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
16284                    class: 'form__ui-select width-650'
16285                },
16286                uiSelectOptions: {
16287                    matchTitle: '{{ $select.selected.name }} ',
16288                    choicesTitle: '{{ item.name }}',
16289                    match: {
16290                        placeholder: 'Страна',
16291                        allowClear: true
16292                    },
16293                    choices: {
16294                        repeat: 'item in field.items track by item.id',
16295                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "Country", "country")',
16296                        refreshDelay: 400
16297                    },
16298                    refreshAutoComplete: autocomplete.refreshAutoComplete,
16299                    onSelect: function( item ) {
16300                        if ( item ) {
16301                            subclubForm.autoCompleteSelect.country = item.id;
16302                            subclubForm.autoCompleteSelect.region = null;
16303                            subclubForm.autoCompleteSelect.city = null;
16304
16305                            subclubForm.$fields.region.items = [];
16306                            subclubForm.$fields.city.items = [];
16307                        }
16308                    }
16309                }
16310         
16310   }, autocomplete.get('country'))
16311            .addField('region', 'uiSelect', {
16312                validators: {
16313                    required: false
16314                },
16315                options: {
16316                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
16317                    class: 'form__ui-select width-650'
16318                },
16319                uiSelectOptions: {
16320                    matchTitle: '{{ $select.selected.name }} ',
16321                    choicesTitle: '{{ item.name }}',
16322                    match: {
16323                        placeholder: 'Регион',
16324                        allowClear: true
16325                    },
16326                    choices: {
16327                        repeat: 'item in field.items track by item.id',
16328                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "KladrRegion", "region")',
16329                        refreshDelay: 400
16330                    },
16331                    refreshAutoComplete: function(name, term, object) {
16332                        return autocomplete.refreshAutoComplete(name, term, object, subclubForm.autoCompleteSelect)
16333                    },
16334                    onSelect: function( item ) {
16335                        if ( item ) {
16336                            subclubForm.autoCompleteSelect.region = item.id;
16337                            subclubForm.$fields.city.items = [];
16338                        }
16339                    }
16340                }
16341            }, autocomplete.get('region'))
16342            .addField('city', 'uiSelect', {
16343                validators: {
16344                    required: false
16345                },
16346                options: {
16347                    onSelect: 'field.uiSelectOptions.onSelect($item, $model)',
16348                    class: 'form__ui-select width-650'
16349                },
16350                uiSelectOptions: {
16351                    matchTitle: '{{ $select.selected.name }} ',
16352                    choicesTitle: '{{ item.name }}',
16353                    match: {
16354                        placeholder: 'Населенный пункт',
16355                        allowClear: true
16356                    },
16357                    choices: {
16358                        repeat: 'item in field.items track by item.id',
16359                        refresh: 'field.uiSelectOptions.refreshAutoComplete($select.search, "KladrCity", "city")',
16360                        refreshDelay: 400
16361                    },
16362                    refreshAutoComplete: function(name, term, object) {
16363                        return autocomplete.refreshAutoComplete(name, term, object, subclubForm.autoCompleteSelect)
16364                    }
16365                }
16366            }, autocomplete.get('city'))
16367            .addField('address', 'text', {
16368                validators: {
16369                    required: false
16370                },
16371                options: {
16372                    placeholder: 'Адрес'
16373                }
16374            })
16375            .addField('phone', 'text', {
16376                validators: {
16377                    required: false
16378                },
16379                options: {
16380                    placeholder: 'Телефон'
16381                }
16382            })
16383            .addField('email', 'text', {
16384                validators: {
16385                    required: false
16386                },
16387                options: {
16388                    placeholder: 'E-mail'
16389                }
16390            })
16391            .addField('www', 'text', {
16392                validators: {
16393                    required: false
16394                },
16395                options: {
16396                    placeholder: 'Сайт'
16397                }
16398            })
16399            .addField('user', 'userSelect', {
16400                validators: {
16401                    required: true
16402                },
16403                uiSelectOptions: {
16404                    match: {
16405                        placeholder: 'Имя и фамилия руководителя'
16406                    }
16407                }
16408            }, autocomplete.get('users'))
16409            .addField('avatar', 'imageUpload', {
16410                validators: {
16411                    required: false
16412                },
16413                uploader: {
16414                    url: Routing.generate('api_upload_post_avatar', {thumb: 'avatar_relative'}),
16415                    autoUpload: true,
16416                    removeAfterUpload: true,
16417                    onWhenAddingFileFailed: function(item, filter) {
16418                        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
16419                        showModalMessage(message);
16420                    },
16421                    onErrorItem: function() {
16422                        showModalMessage('Невозможно загрузить файл на сервер');
16423                    }
16424                }
16425            })
16426            .addField('social_vk', 'text', {
16427                validators: {
16428                    required: false
16429                },
16430                options: {
16431                    placeholder: 'Вконтакте'
16432                }
16433            })
16434            .addField('social_fb', 'text', {
16435                validators: {
16436                    required: false
16437                },
16438                options: {
16439                    placeholder: 'Facebook'
16440                }
16441            })
16442            .addField('social_in', 'text', {
16443                validators: {
16444                    required: false
16445                },
16446                options: {
16447                    placeholder: 'Instagram'
16448                }
16449            });
16450
16451        return subclubForm;
16452}]);
16453
16454},{"../helpers/show-modal-message/show-modal-message":167,"../modules/forms/forms":244}],157:[function(require,module,exports){
16455require('./customPartner.theme');
16456
16457require('./row');
16458
16459require('./fields/imageUpload');
16460require('./fields/text');
16461require('./fields/url');
16462
16463},{"./customPartner.theme":158,"./fields/imageUpload":159,"./fields/text":160,"./fields/url":161,"./row":162}],158:[function(require,module,exports){
16464'use strict';
16465
16466angular.module('dekky.forms.themes.customPartner', []);
16467
16468},{}],159:[function(require,module,exports){
16469'use strict';
16470
16471angular.module('dekky.forms.themes.customPartner')
16472.run(["$templateCache", function($templateCache) {
16473	$templateCache.put('/dekky.forms/themes/customPartner/fields/imageUpload.html',
16474		'<span ng-init="model = uploader.queue">' +
16475			'<ul class="form-list">' +
16476				'<li class="form-list__item form-list__item_icon" ng-repeat="item in uploader.queue">' +
16477					'<span class="form-list__link" ng-if="item.isUploaded && item.isSuccess">{{ item.file.name }}</span>' +
16478					'<span ng-if="item.isUploaded && item.isError" class="relative">' +
16479						'<span class="form-list__link">{{ item.file.name }}</span>'+
16480						'<span class="form__error_inline">Ошибка</span>' +
16481					'</span>' +
16482					'<span class="form-list__item-close" ng-click="item.remove()"></span>' +
16483					'<span class="" ng-if="item.isUploading"><i class="fa fa-spinner fa-pulse"></i></span>' +
16484				'</li>' +
16485			'</ul>' +
16486			'<input class="btn-file-upload__input" id="{{ field.name + \'_\' + fieldIndex }}" type="file" nv-file-select uploader="uploader" filters="images">' +
16487		'</span>'
16488	);
16489}]);
16490
16491},{}],160:[function(require,module,exports){
16492'use strict';
16493
16494angular.module('dekky.forms.themes.customPartner')
16495.run(["$templateCache", function($templateCache) {
16496	$templateCache.put('/dekky.forms/themes/customPartner/fields/text.html',
16497		'<input type="text" class="form__item" ng-model="model" name="{{ field.name }}" id="{{ field.name }}">'
16498	);
16499}]);
16500
16501},{}],161:[function(require,module,exports){
16502'use strict';
16503
16504angular.module('dekky.forms.themes.customPartner')
16505.run(["$templateCache", function($templateCache) {
16506	$templateCache.put('/dekky.forms/themes/customPartner/fields/url.html',
16507		'<input type="url" class="form__item" ng-model="model" name="{{ field.name }}" id="{{ field.name }}">{{index}}'
16508	);
16509}]);
16510
16511},{}],162:[function(require,module,exports){
16512'use strict';
16513
16514angular.module('dekky.forms.themes.customPartner')
16515	.run(["$templateCache", function($templateCache) {
16516		$templateCache.put('/dekky.forms/themes/customPartner/row.html',
16517			'<div class="form-group" ng-class="{\'btn-file-upload\': field.type == \'imageUpload\'}">' +
16518				'<form-widget field="field" ng-model="model" field-index="fieldIndex"></form-widget>' +
16519				'<label for="{{ field.name + \'_\' + fieldIndex }}" ng-if="field.label">{{ field.label }}</label>' +
16520			'</div>'
16521		);
16522	}]);
16523
16524},{}],163:[function(require,module,exports){
16525'use strict';
16526
16527angular.module('dekky.forms.themes.inviteUser', [])
16528.run(["$templateCache", function($templateCache) {
16529	$templateCache.put('/dekky.forms/themes/inviteUser/collection.html',
16530		'<div ng-init="model = model || []" ng-model="model">' +
16531			'<div repeat-collection class="panel panel-default" ng-form="childForm">' +
16532				'<div class="panel-body">' +
16533					'<div class="form-items">' +
16534						'<form-row ng-repeat="(key, itemField) in field.childForm.$fields" ng-model="item[key]" ng-model-options="{ updateOn: \'blur\' }" field="itemField"></form-row>' +
16535						'<p class="form__error" ng-if="childForm.$dirty" ng-messages="childForm.$error" role="alert">' +
16536							'<span ng-message="uniqueUser">Такой email уже зарегистрирован на сайте</span>' +
16537							'<span ng-message="required">Заполните все поля</span>' +
16538						'</p>' +
16539					'</div>' +
16540					'<a class="btn-link margin_b_20 right" ng-click="field.doDelete(item, model, $index)">{{ field.buttons.remove }}</a>' +
16541				'</div>' +
16542			'</div>' +
16543
16544			'<div class="form-group">' +
16545				'<a class="btn-link margin_b_40" ng-click="field.addItem(model)">{{ field.buttons.add }}</a>' +
16546			'</div>' +
16547		'</div>'
16548	);
16549}]);
16550
16551},{}],164:[function(require,module,exports){
16552'use strict';
16553
16554angular.module('dekky.forms.themes.typeaheadUser', [])
16555.run(["$templateCache", function($templateCache) {
16556	$templateCache.put('/dekky.forms/themes/typeaheadUser/typeahead-match.html',
16557	    '<a href tabindex="-1" ng-bind-html="match.label.fio | uibTypeaheadHighlight:query" ng-attr-title="{{match.label.fio}}"></a><p ng-if="match.label.p0" ng-bind="match.label.p0"></p><p ng-if="match.label.p1" ng-bind="match.label.p1"></p>'
16558	);
16559}]);
16560
16561},{}],165:[function(require,module,exports){
16562'use strict';
16563
16564angular.module('far.helpers.guid', [])
16565.service('guid', function() {
16566  function guid() {
16567      function s4() {
16568          return Math.floor((1 + Math.random()) * 0x10000)
16569              .toString(16)
16570              .substring(1);
16571      }
16572      
16573      return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
16574          s4() + '-' + s4() + s4() + s4();
16575  }
16576
16577  return guid;
16578});
16579
16580},{}],166:[function(require,module,exports){
16581'use strict';
16582
16583angular.module('far.helpers.rawFilter', [])
16584.filter('rawHtml', ["$sce", function($sce){
16585  return function(val) {
16586    return $sce.trustAsHtml(val);
16587  };
16588}]);
16589
16590},{}],167:[function(require,module,exports){
16591'use strict';
16592
16593require('../../modals/message-popup/message-popup');
16594
16595angular.module('far.helpers.showModalMessage', [
16596	'ui.bootstrap',
16597	'far.modals.message-popup',
16598	'templates'
16599])
16600.service('showModalMessage', ["$uibModal", function($uibModal) {
16601	function showModalMessage(messages, title) {
16602		var data = {
16603			title: function() {
16604				return title;
16605			},
16606			messages: function() {
16607				if (angular.isArray(messages)) {
16608					return messages;
16609				}
16610
16611				return [messages];
16612			}
16613		};
16614
16615		var modalInstance = $uibModal.open({
16616			templateUrl: '/modals/message-popup/message-popup.html',
16617			windowClass: 'modal-notice',
16618			controller: 'MessagePopupController as messagePopup',
16619			resolve: data
16620		});
16621
16622		return modalInstance;
16623	}
16624
16625	return showModalMessage;
16626}]);
16627
16628},{"../../modals/message-popup/message-popup":172}],168:[function(require,module,exports){
16629(function () {
16630    var module = angular.module('far.helpers.stripTagsFilter', []);
16631
16632    module.filter('stripTags', stripTags);
16633
16634    function stripTags() {
16635        return function(value) {
16636            if (!value) {
16637                return value;
16638            }
16639
16640            return $($.parseHTML('<root>' + value + '</root>')).text();
16641        }
16642    }
16643})();
16644
16645},{}],169:[function(require,module,exports){
16646'use strict';
16647
16648require('../../models/user/userRelation');
16649
16650angular.module('far.helpers.users', [
16651    'far.models.userRelation'
16652])
16653    .filter('userType', function () {
16654        return function (users, userType) {
16655            return users.filter(function (user) {
16656                return user[user.relation].id == userType.id;
16657            });
16658        };
16659    })
16660    .service('usersHelper', ["UserRelation", function (UserRelation) {
16661        var addUsersRelation = function (model, usersRelation) {
16662            Object.defineProperty(model, '_usersRelation', {
16663                enumerable: false,
16664                writable: false,
16665                value: usersRelation
16666            });
16667        }
16668        var addUsersArray = function (model, usersArrayProperty) {
16669            Object.defineProperty(model, '_usersArray', {
16670                enumerable: false,
16671                writable: false,
16672                value: usersArrayProperty
16673            });
16674        };
16675        var addUserTypes = function (model, userTypes) {
16676            Object.defineProperty(model, 'userTypes', {
16677                enumerable: false,
16678                writable: false,
16679                value: userTypes
16680            });
16681        };
16682        var addCreateUserFunc = function (model, usersArrayProperty) {
16683            Object.defineProperty(model, 'createUser', {
16684                enumerable: false,
16685                writable: false,
16686                value: function (userType) {
16687                    var newUndefinedUser = UserRelation.newUndefined(model._usersRelation, userType);
16688                    this[usersArrayProperty].push(newUndefinedUser);
16689
16690                    return newUndefinedUser;
16691                }
16692            });
16693        };
16694        var addUpdateUsersFunc = function (model, usersArrayProperty) {
16695            Object.defineProperty(model, 'updateUsers', {
16696                enumerable: false,
16697                writable: false,
16698                value: function () {
16699                    this[usersArrayProperty] = this[usersArrayProperty].map(function (user) {
16700                        return UserRelation.new(user);
16701                    });
16702                }
16703            });
16704        };
16705        var addUpdateUserFunc = function (model, usersArrayProperty) {
16706            Object.defineProperty(model, 'updateUser', {
16707                enumerable: false,
16708                writable: false,
16709                value: function (uniqId, newUserData) {
16710                    this[usersArrayProperty].filter(function (user) {
16711                        return user.uniqId == uniqId;
16712                    })[0].user = angular.isObject(newUserData) ? newUserData : undefined;
16713                }
16714            });
16715        };
16716        var addDeleteUserFunc = function (model, usersArrayProperty) {
16717            Object.defineProperty(model, 'deleteUser', {
16718                enumerable: false,
16719                writable: false,
16720                value: function (deleteUser) {
16721                    this[usersArrayProperty] = this[usersArrayProperty].filter(function (user) {
16722                        return user.uniqId != deleteUser.uniqId;
16723                    });
16724                }
16725            });
16726        };
16727
16728        this.addFields = function (model, userTypes, usersArrayProperty, usersRelation) {
16729            addUsersRelation(model, usersRelation);
16730            addUserTypes(model, userTypes);
16731            addUsersArray(model, usersArrayProperty);
16732            addCreateUserFunc(model, usersArrayProperty);
16733            addUpdateUsersFunc(model, usersArrayProperty);
16734            addUpdateUserFunc(model, usersArrayProperty);
16735            addDeleteUserFunc(model, usersArrayProperty);
16736        };
16737
16738        this.initUsers = function (model, userTypes, usersArrayProperty, usersRelation) {
16739            this.addFields(model, userTypes, usersArrayProperty, usersRelation);
16740
16741            model[usersArrayProperty] = model[usersArrayProperty].map(function (user) {
16742                return UserRelation.new(user);
16743            });
16744        };
16745
16746    }]);
16747
16748},{"../../models/user/userRelation":234}],170:[function(require,module,exports){
16749'use strict';
16750
16751angular.module('far.modals.message-popup', [])
16752.controller('MessagePopupController', ["$uibModalInstance", "messages", "title", function($uibModalInstance, messages, title) {
16753	var vm = {
16754		close: function() {
16755			$uibModalInstance.close();
16756		}
16757	};
16758
16759	if (!title && messages.length == 1) {
16760		vm.message = messages[0];
16761	} else {
16762		vm.title = title;
16763		vm.messages = messages;
16764	}
16765
16766	return vm;
16767}]);
16768
16769},{}],171:[function(require,module,exports){
16770var ngModule;
16771try {
16772  ngModule = angular.module('templates');
16773} catch (e) {
16774  ngModule = angular.module('templates', []);
16775}
16776
16777ngModule.run(['$templateCache', function ($templateCache) {
16778  $templateCache.put('/modals/message-popup/message-popup.html',
16779    '<div class="modal-body" ng-click="messagePopup.close()">\n' +
16780    '    <button class="close"></button>\n' +
16781    '    <div ng-if="messagePopup.message">\n' +
16782    '        <p class="modal-info__text">{{ messagePopup.message }}</p>\n' +
16783    '    </div>\n' +
16784    '    <div ng-if="messagePopup.messages">\n' +
16785    '        <p class="modal-info__text">{{ messagePopup.title }}</p>\n' +
16786    '        <ul class="modal-info__text">\n' +
16787    '            <li style="list-style-type: disc;" ng-repeat="message in messagePopup.messages track by $index">{{ message }};</li>\n' +
16788    '        </ul>\n' +
16789    '    </div>\n' +
16790    '</div>');
16791}]);
16792
16793module.exports = "/modals/message-popup/message-popup.html";
16794},{}],172:[function(require,module,exports){
16795require('./message-popup.html');
16796require('./message-popup.controller');
16797
16798},{"./message-popup.controller":170,"./message-popup.html":171}],173:[function(require,module,exports){
16799'use strict';
16800
16801require('../../forms/mountainRouteForm');
16802require('../../models/mountains/routes');
16803
16804angular.module('far.modals.mountain-route-form', [
16805	'far.forms.mountainRouteForm',
16806	'far.models.mountains.routes'
16807])
16808.controller('MountainRouteFormController', ["$log", "$uibModalInstance", "mountainRouteForm", "mountainRoutes", "selectedPeak", function(
16809	$log,
16810	$uibModalInstance,
16811	mountainRouteForm,
16812	mountainRoutes,
16813	selectedPeak
16814) {
16815	var vm = {
16816		mountainRouteModel: mountainRouteForm,
16817		mountainRoute: mountainRoutes.new({
16818			mountain_peaks: [undefined],
16819			slides_files: [],
16820			documents_files: []
16821		}),
16822		submit: submit,
16823		getDocumentUrl: getDocumentUrl,
16824		close: function() {
16825			$uibModalInstance.dismiss();
16826		}
16827	};
16828
16829	vm.mountainRouteModel.$fields.description.options.class = 'form__item';
16830	vm.mountainRouteModel.$fields.mountain_peak.uiSelectOptions.onSelect = function(item, model, options) {
16831		if (item) { vm.mountainRoute.mountain_peaks[options.index] = item; }
16832	};
16833	vm.mountainRouteModel.$fields.routeType.options.class = 'form__item form__item_select width-200 margin_r_20';
16834	vm.mountainRouteModel.$fields.routeComplexity.options.class = 'form__item form__item_select width-200 margin_r_20';
16835	vm.mountainRouteModel.$fields.routeUser.options.class = 'form__ui-select width-340';
16836	vm.mountainRouteModel.$fields.routeUser.uiSelectOptions.onSelect = function (item) {
16837		if (item) { vm.mountainRoute.user = item; }
16838	};
16839	vm.mountainRouteModel.$fields.documentsFiles.uploader.removeFromQueue = function (value) {
16840		var index = this.getIndexOfItem(value);
16841		var item = this.queue[index];
16842
16843		if (item.isUploading) {
16844			item.cancel();
16845		} else {
16846			vm.documents_files.splice(index, 1);
16847		}
16848
16849		this.queue.splice(index, 1);
16850		item._destroy();
16851
16852		this.progress = this._getTotalProgress();
16853	};
16854
16855	if (selectedPeak) {
16856		vm.mountainRoute.mountain_peaks[0] = selectedPeak;
16857	}
16858
16859	function getDocumentUrl(file_id) {
16860		return Routing.generate('api_upload_get_file', {fileStorage: file_id});
16861	}
16862
16863	function submit() {
16864		vm.mountainRoute.documents_files = vm.mountainRoute.documents_files.concat(
16865			vm.documents_files
16866				.filter(function(document) {
16867					return document.isUploaded;
16868				})
16869				.map(function(document) {
16870					return document.serverData;
16871				})
16872		);
16873		vm.mountainRouteModel.$fields.documentsFiles.uploader.clearQueue();
16874
16875		vm.mountainRoute.slides_files = vm.mountainRoute.slides_files.map(function(slide, index) {
16876			slide.sort = index + 1;
16877			return slide;
16878		});
16879
16880		vm.mountainRoute.save()
16881			.then(function(response) {
16882				$uibModalInstance.close(response.data);
16883			})
16884			.catch(function (response) {
16885				$log.error(response);
16886			});
16887	}
16888
16889	return vm;
16890}]);
16891
16892},{"../../forms/mountainRouteForm":152,"../../models/mountains/routes":217}],174:[function(require,module,exports){
16893var ngModule;
16894try {
16895  ngModule = angular.module('templates');
16896} catch (e) {
16897  ngModule = angular.module('templates', []);
16898}
16899
16900ngModule.run(['$templateCache', function ($templateCache) {
16901  $templateCache.put('/modals/mountain-route-form/mountain-route-form.html',
16902    '<div class="modal-body">\n' +
16903    '	<h2 class="margin_b_20">Добавить новый маршрут</h2>\n' +
16904    '	<form class="form ng-hide" name="mountainRouteForm" ng-submit="mountainRouteForm.$valid && routeForm.submit()" ng-show="!routeForm.progress">\n' +
16905    '		<form-widget field="routeForm.mountainRouteModel.$fields.slides"    ng-model="routeForm.mountainRoute.slides"></form-widget>\n' +
16906    '		<form-widget field="routeForm.mountainRouteModel.$fields.documents" ng-model="routeForm.mountainRoute.documents"></form-widget>\n' +
16907    '\n' +
16908    '		<fieldset class="form__fieldset width-350">\n' +
16909    '			<h3 class="page__title_xs">Название маршрута</h3>\n' +
16910    '			<form-row field="routeForm.mountainRouteModel.$fields.name" ng-model="routeForm.mountainRoute.name"></form-row>\n' +
16911    '			<div ng-if="mountainRouteForm.$submitted && mountainRouteForm.name.$error.required" class="form__error" role="alert">Обязательное поле</div>\n' +
16912    '		</fieldset>\n' +
16913    '\n' +
16914    '		<fieldset class="form__fieldset width-350">\n' +
16915    '			<h3 class="page__title_xs">Год прохождения</h3>\n' +
16916    '			<form-row field="routeForm.mountainRouteModel.$fields.first_ascent_year" ng-model="routeForm.mountainRoute.first_ascent_year"></form-row>\n' +
16917    '		</fieldset>\n' +
16918    '\n' +
16919    '		<fieldset class="form__fieldset width-350">\n' +
16920    '			<h3 class="page__title_xs">Вершина</h3>\n' +
16921    '			<div ng-repeat="mountain_peak in routeForm.mountainRoute.mountain_peaks" class="margin_b_20">\n' +
16922    '				<form-row field="routeForm.mountainRouteModel.$fields.mountain_peak" ng-model="mountain_peak" ng-model-options="{ index: $index }"></form-row>\n' +
16923    '				<span ng-click="routeForm.mountainRoute.mountain_peaks.splice($index,1)" ng-if="$index>
169230" class="btn-link profile-ascent__btn_delete">Удалить траверс</span>\n' +
16924    '			</div>\n' +
16925    '			<span ng-click="routeForm.mountainRoute.mountain_peaks.push({})" class="btn-link profile-ascent__btn_add margin_b_40">Добавить траверс</span>\n' +
16926    '		</fieldset>\n' +
16927    '\n' +
16928    '		<fieldset class="form__fieldset">\n' +
16929    '			<h3 class="page__title_xs">Характеристики маршрута</h3>\n' +
16930    '\n' +
16931    '			<div class="form-group_inline">\n' +
16932    '				<form-row field="routeForm.mountainRouteModel.$fields.routeType" ng-model="routeForm.mountainRoute.mountain_route_type"></form-row>\n' +
16933    '				<div ng-if="mountainRouteForm.$submitted && mountainRouteForm.routeType.$error.required" class="form__error" role="alert">Обязательное поле</div>\n' +
16934    '			</div>\n' +
16935    '\n' +
16936    '			<div class="form-group_inline">\n' +
16937    '				<form-row field="routeForm.mountainRouteModel.$fields.routeComplexity" ng-model="routeForm.mountainRoute.mountain_route_complexity"></form-row>\n' +
16938    '				<div ng-if="mountainRouteForm.$submitted && mountainRouteForm.routeComplexity.$error.required" class="form__error" role="alert">Обязательное поле</div>\n' +
16939    '			</div>\n' +
16940    '\n' +
16941    '			<div class="form-group_inline">\n' +
16942    '				<form-row field="routeForm.mountainRouteModel.$fields.routeUser" ng-model="routeForm.mountainRoute.user"></form-row>\n' +
16943    '				<div ng-if="mountainRouteForm.$submitted && mountainRouteForm.routeUser.$error.required" class="form__error" role="alert">Обязательное поле</div>\n' +
16944    '			</div>\n' +
16945    '		</fieldset>\n' +
16946    '\n' +
16947    '		<fieldset class="form__fieldset">\n' +
16948    '			<h3 class="page__title_xs">Описание маршрута</h3>\n' +
16949    '			<form-row field="routeForm.mountainRouteModel.$fields.description" ng-model="routeForm.mountainRoute.description"></form-row>\n' +
16950    '		</fieldset>\n' +
16951    '\n' +
16952    '		<fieldset class="form__fieldset margin_b_40">\n' +
16953    '			<h3 class="page__title_xs">Прикрепить файл</h3>\n' +
16954    '\n' +
16955    '			<ul class="form-list">\n' +
16956    '				<li class="form-list__item form-list__item_icon" ng-repeat="item in routeForm.documents_files" ng-class="{\'df-uploader__list-item--error\': item.isError}">\n' +
16957    '                    <span class="relative">\n' +
16958    '                        <a class="form-list__link" ng-if="item.isUploaded" ng-href="{{ routeForm.getDocumentUrl(item.serverData.id) }}" target="_blank">\n' +
16959    '							<span ng-bind="item.file.name"></span>\n' +
16960    '						</a>\n' +
16961    '                        <span class="form-list__item-close" ng-click="item.remove()"></span>\n' +
16962    '                        <p class="form__error_inline" ng-if="item.isError">Ошибка</p>\n' +
16963    '                    </span>\n' +
16964    '					<span class="" ng-if="item.isUploading"><i class="fa fa-spinner fa-pulse"></i></span>\n' +
16965    '				</li>\n' +
16966    '			</ul>\n' +
16967    '\n' +
16968    '			<form-row field="routeForm.mountainRouteModel.$fields.documentsFiles" ng-model="routeForm.documents_files" class="btn-file-upload"></form-row>\n' +
16969    '\n' +
16970    '		</fieldset>\n' +
16971    '		\n' +
16972    '		<div class="form__line"></div>\n' +
16973    '\n' +
16974    '		<div class="form-group">\n' +
16975    '			<button type="submit" class="btn-gold_big">Отправить описание</button>\n' +
16976    '		</div>\n' +
16977    '	</form>\n' +
16978    '</div>\n' +
16979    '<button class="close" ng-click="routeForm.close()"></button>');
16980}]);
16981
16982module.exports = "/modals/mountain-route-form/mountain-route-form.html";
16983},{}],175:[function(require,module,exports){
16984require('./mountain-route-form.html');
16985require('./mountain-route-form.controller');
16986
16987},{"./mountain-route-form.controller":173,"./mountain-route-form.html":174}],176:[function(require,module,exports){
16988'use strict';
16989
16990require('../../modules/forms/forms');
16991require('../../helpers/show-modal-message/show-modal-message');
16992
16993angular.module('far.modals.mountain-route-images', [
16994  'angularFileUpload',
16995  'dekky.forms',
16996  'far.helpers.showModalMessage'
16997])
16998.controller('MountainRouteImagesController', ["$uibModalInstance", "FileUploader", "fileUploadFilters", "mountainRoute", "showModalMessage", "isAdmin", function(
16999  $uibModalInstance,
17000  FileUploader,
17001  fileUploadFilters,
17002  mountainRoute,
17003  showModalMessage,
17004  isAdmin
17005) {
17006  var vm = {
17007    isAdmin: isAdmin,
17008    slidesFiles: new FileUploader({
17009      url: Routing.generate('api_upload_post_image'),
17010      autoUpload: true,
17011      filters: [fileUploadFilters.fileType('png', 'jpg', 'jpeg'), fileUploadFilters.fileSize()],
17012      onWhenAddingFileFailed: function(item, filter) {
17013        var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
17014        showModalMessage(message);
17015      },
17016      onErrorItem: function(item) {
17017        showModalMessage('Невозможно загрузить файл на сервер');
17018        item.remove();
17019      },
17020      onSuccessItem: function(item, response) {
17021        item.serverData = response;
17022      }
17023    }),
17024    close: function() {
17025			$uibModalInstance.dismiss();
17026		},
17027    submitChanges: function() {
17028      mountainRoute.slides_files = vm.slidesFiles.queue.map(function(slide, index) {
17029          slide.serverData.sort = index + 1;
17030          return slide.serverData;
17031      });
17032
17033      mountainRoute.save()
17034          .then(function () {
17035              $uibModalInstance.close();
17036          })
17037          .catch(function(response) {
17038              $uibModalInstance.dismiss({error: 'Возникла проблема при сохранении изменений. Попробуйте позже.'});
17039          });
17040    }
17041  };
17042
17043  mountainRoute.slides_files.forEach(function(serverFile) {
17044    var newFile = new FileUploader.FileItem(vm.slidesFiles, {
17045      lastModifiedDate: new Date(),
17046      size: 1e6,
17047      image_name: serverFile.original_name
17048    });
17049
17050    newFile.progress = 100;
17051    newFile.isUploaded = true;
17052    newFile.isSuccess = true;
17053    newFile.serverData = angular.merge({}, serverFile);
17054
17055    vm.slidesFiles.queue.push(newFile);
17056  });
17057
17058  return vm;
17059}]);
17060
17061},{"../../helpers/show-modal-message/show-modal-message":167,"../../modules/forms/forms":244}],177:[function(require,module,exports){
17062var ngModule;
17063try {
17064  ngModule = angular.module('templates');
17065} catch (e) {
17066  ngModule = angular.module('templates', []);
17067}
17068
17069ngModule.run(['$templateCache', function ($templateCache) {
17070  $templateCache.put('/modals/mountain-route-images/mountain-route-images.html',
17071    '<div class="modal-body">\n' +
17072    '	<h2 class="margin_b_20">Добавить новые фотографии</h2>\n' +
17073    '\n' +
17074    '  <div class="clearfix" ng-repeat="image in routeImages.slidesFiles.queue">\n' +
17075    '    <div class="form__fieldset center" ng-if="image.isUploading">\n' +
17076    '      <button class="btn-show btn-show_active">Загружаю</button>\n' +
17077    '    </div>\n' +
17078    '    <div class="form__fieldset" ng-if="image.isUploaded">\n' +
17079    '      <div class="form-group_inline width-350">\n' +
17080    '        <img class="img-responsive" ng-src="{{ image.serverData.thumb_path }}">\n' +
17081    '      </div>\n' +
17082    '      <div class="form-group_inline width-350">\n' +
17083    '        <textarea class="form__item" ng-model="image.serverData.description"></textarea>\n' +
17084    '      </div>\n' +
17085    '      <button type="button" class="btn-standart right" ng-click="image.remove()" ng-if="routeImages.isAdmin">Удалить</button>\n' +
17086    '    </div>\n' +
17087    '  </div>\n' +
17088    '\n' +
17089    '  <div class="form__fieldset">\n' +
17090    '    <button type="button" class="btn-standart relative">Добавить фотографию\n' +
17091    '        <input class="docs__input_file" type="file" nv-file-select uploader="routeImages.slidesFiles" />\n' +
17092    '    </button>\n' +
17093    '  </div>\n' +
17094    '\n' +
17095    '  <div class="form__line"></div>\n' +
17096    '  <div class="form-group">\n' +
17097    '    <button type="button" class="btn-gold_big" ng-click="routeImages.submitChanges()">Сохранить изменения</button>\n' +
17098    '  </div>\n' +
17099    '</div>\n' +
17100    '<button class="close" ng-click="routeImages.close()"></button>\n' +
17101    '');
17102}]);
17103
17104module.exports = "/modals/mountain-route-images/mountain-route-images.html";
17105},{}],178:[function(require,module,exports){
17106require('./mountain-route-images.html');
17107require('./mountain-route-images.controller');
17108
17109},{"./mountain-route-images.controller":176,"./mountain-route-images.html":177}],179:[function(require,module,exports){
17110var ngModule;
17111try {
17112  ngModule = angular.module('templates');
17113} catch (e) {
17114  ngModule = angular.module('templates', []);
17115}
17116
17117ngModule.run(['$templateCache', function ($templateCache) {
17118  $templateCache.put('/modals/slider/carousel.html',
17119    '<div ng-mouseenter="pause()" ng-mouseleave="play()" class="carousel" ng-swipe-right="prev()" ng-swipe-left="next()">\n' +
17120    '    <div class="carousel-inner" ng-transclude></div>\n' +
17121    '    <button class="arrow-left" ng-click="prev()" ng-show="slides.length > 1"></button>\n' +
17122    '    <button class="arrow-right" ng-click="next()" ng-show="slides.length > 1"></button>\n' +
17123    '</div>');
17124}]);
17125
17126module.exports = "/modals/slider/carousel.html";
17127},{}],180:[function(require,module,exports){
17128'use strict';
17129
17130angular.module('far.modals.slider', [])
17131.controller('SliderController', ["$uibModalInstance", "slides", "selectedSlide", function($uibModalInstance, slides, selectedSlide) {
17132	var vm = {
17133		slides: slides.map(function(slide) {
17134			slide.active = slide.id == selectedSlide.id;
17135			slide.style = {
17136				'background-image': 'url(' + slide.image_path + ')'
17137			};
17138
17139			return slide;
17140		}),
17141		close: function() {
17142			$uibModalInstance.close();
17143		}
17144	};
17145
17146	return vm;
17147}]);
17148
17149},{}],181:[function(require,module,exports){
17150var ngModule;
17151try {
17152  ngModule = angular.module('templates');
17153} catch (e) {
17154  ngModule = angular.module('templates', []);
17155}
17156
17157ngModule.run(['$templateCache', function ($templateCache) {
17158  $templateCache.put('/modals/slider/slider.html',
17159    '<div class="modal-body">\n' +
17160    '    <uib-carousel no-wrap="true" template-url="/modals/slider/carousel.html">\n' +
17161    '        <uib-slide ng-repeat="slide in slider.slides" active="slide.active">\n' +
17162    '            <div class="carousel-img-wrapper" ng-style="slide.style">\n' +
17163    '                <img class="responsive-img" ng-src="{{ slide.image_path }}">\n' +
17164    '            </div>\n' +
17165    '            <div class="modal-footer">\n' +
17166    '                <!-- <a href="#" class="btn-link modal-popup__edit">Редактировать описание</a> -->\n' +
17167    '                <p ng-if="slide.description">{{ slide.description }}</p>\n' +
17168    '            </div>\n' +
17169    '        </uib-slide>\n' +
17170    '    </uib-carousel>\n' +
17171    '</div>\n' +
17172    '<button class="close" ng-click="slider.close()"></button>');
17173}]);
17174
17175module.exports = "/modals/slider/slider.html";
17176},{}],182:[function(require,module,exports){
17177require('./slider.html');
17178require('./carousel.html');
17179require('./slider.controller');
17180
17181},{"./carousel.html":179,"./slider.controller":180,"./slider.html":181}],183:[function(require,module,exports){
17182'use strict';
17183
17184angular.module('far.models.ascentTypes', [])
17185	.service('ascentTypes', ["$log", "$http", function ($log, $http) {
17186		var list = [],
17187			firstListQuery = true,
17188			listQueryProgress = false;
17189
17190		Object.defineProperty(this, 'list', {
17191			get: function () {
17192				if (firstListQuery && !listQueryProgress) {
17193					listQueryProgress = true;
17194
17195					$http.get(Routing.generate('api_entities_get_ascent_types'))
17196						.then(function (response) {
17197							response.data.forEach(function (routeData) {
17198								list.push(routeData);
17199							});
17200
17201							firstListQuery = false;
17202							listQueryProgress = false;
17203						})
17204						.catch(function (response) {
17205							listQueryProgress = false;
17206							$log.error(response);
17207						});
17208				}
17209
17210				return list;
17211			}
17212		});
17213	}]);
17214
17215},{}],184:[function(require,module,exports){
17216
17217'use strict';
17218
17219angular.module('far.models.ascentUserTypes', [])
17220	.service('ascentUserTypes', ["$log", "$http", function ($log, $http) {
17221		var list = [],
17222			firstListQuery = true,
17223			listQueryProgress = false;
17224
17225		Object.defineProperty(this, 'list', {
17226			get: function () {
17227				if (firstListQuery && !listQueryProgress) {
17228					listQueryProgress = true;
17229
17230					$http.get(Routing.generate('api_entities_get_ascent_user_types'))
17231						.then(function (response) {
17232							response.data.forEach(function (routeData) {
17233								list.push(routeData);
17234							});
17235
17236							firstListQuery = false;
17237							listQueryProgress = false;
17238						})
17239						.catch(function (response) {
17240							listQueryProgress = false;
17241							$log.error(response);
17242						});
17243				}
17244
17245				return list;
17246			}
17247		});
17248	}]);
17249
17250},{}],185:[function(require,module,exports){
17251'use strict';
17252
17253require('../../helpers/users/users.module');
17254
17255angular.module('far.models.ascents', ['far.helpers.users'])
17256	.service('Ascents', ["$log", "$http", "usersHelper", function($log, $http, usersHelper) {
17257		var list = [],
17258			firstListQuery = true,
17259			listQueryProgress = false;
17260
17261		Object.defineProperty(this, 'list', {
17262			get: function() {
17263				if (firstListQuery && !listQueryProgress) {
17264					listQueryProgress = true;
17265
17266					$http.get(Routing.generate(''))
17267						.then(function(response) {
17268							response.data.forEach(function(routeData) {
17269								list.push(new Ascent(routeData));
17270							});
17271
17272							firstListQuery = false;
17273							listQueryProgress = false;
17274						})
17275						.catch(function(response) {
17276							listQueryProgress = false;
17277							$log.error(response);
17278						});
17279				}
17280
17281				return list;
17282			}
17283		});
17284
17285		this.new = function(ascentData, userTypes) {
17286			return new Ascent(ascentData, userTypes);
17287		};
17288
17289		this.delete = function(ascent, callback) {
17290			return $http.delete(Routing.generate('api_entities_delete_ascent', {ascent: ascent.id}))
17291				.then(function() {
17292					ascent = null;
17293
17294          if (typeof callback == 'function') {
17295              callback();
17296          }
17297				})
17298				.catch(function(response) {
17299					$log.error(response);
17300				});
17301		};
17302
17303		this.restore = function(ascent, callback) {
17304			return $http.patch(Routing.generate('api_entities_patch_ascent', {id: ascent.id}))
17305				.then(function() {
17306					if (typeof callback == 'function') {
17307						callback(ascent);
17308					}
17309				})
17310				.catch(function(response) {
17311					$log.error(response);
17312				});
17313		};
17314
17315		this.get = function(ascentId, userTypes, callback) {
17316			var route = new Ascent({}, userTypes);
17317
17318			$http.get(Routing.generate('api_entities_get_ascent', {ascent: ascentId}))
17319				.then(function(response) {
17320                    var chief = true,
17321						instructor = true;
17322
17323                    angular.forEach(response.data.ascent_users, function (user) {
17324                        if(user.ascent_user_type_id.system_name == 'chief') {
17325                            chief = false;
17326                        }
17327                        if(user.ascent_user_type_id.system_name == 'instructor') {
17328                            instructor = false;
17329                        }
17330                    });
17331
17332                    if (chief) {
17333                        response.data.ascent_users.push({
17334                            ascent_user_type_id: userTypes.chief
17335                        });
17336                    }
17337
17338                    if(instructor){
17339                    	response.data.ascent_users.push({ascent_user_type_id: userTypes.instructor});
17340					}
17341
17342					route.update(response.data);
17343
17344					if (typeof callback == 'function') {
17345						callback(route);
17346					}
17347				})
17348				.catch(function(response) {
17349					$log.error(response);
17350				});
17351
17352			return route;
17353		};
17354
17355
17356
17357		function Ascent(ascentData, userTypes) {
17358			this.ascent_users = [];
17359			this.documents_files = [];
17360			angular.merge(this, ascentData);
17361
17362			Object.defineProperty(this, 'update', {
17363				enumerable: false,
17364				get: function() {
17365					return function(ascentData) {
17366						angular.merge(this, ascentData);
17367						this.updateUsers();
17368
17369						return this;
17370					}
17371				}
17372			});
17373
17374			Object.defineProperty(this, 'save', {
17375				enumerable: false,
17376				get: function() {
17377					return function() {
17378						var method = this.id ? 'put' : 'post',
17379								url = this.id ?
17380									Routing.generate('api_entities_put_ascent', {ascent: this.id}) :
17381									Routing.generate('api_entities_post_ascent');
17382						var data = angular.extend({}, this);
17383
17384						data.ascent_users = data.ascent_users.filter(function (user) {
17385							if (user.user) {
17386								return true;
17387							}
17388						});
17389
17390						data.ascent_mountain_route = data.ascent_mountain_route.id;
17391
17392						if (angular.isObject(data.ascent_type)) {
17393							data.ascent_type = data.ascent_type.id;
17394						}
17395
17396						angular.forEach(data.documents_files, function(document_file, i) {
17397							data.documents_files[i]=document_file.id;
17398						});
17399
17400						return $http[method](url, data);
17401					}
17402				}
17403			});
17404			usersHelper.initUsers(this, userTypes, 'ascent_users', 'ascent_user_type_id');
17405			this.createUser(this.userTypes.chief);
17406			this.createUser(this.userTypes.instructor);
17407		}
17408	}]);
17409
17410},{"../../helpers/users/users.module":169}],186:[function(require,module,exports){
17411'use strict';
17412
17413angular.module('far.models.post', [])
17414    .service('Post', ["$log", "$http", function($log, $http) {
17415        this.new = function (data) {
17416            return new Post(data);
17417        };
17418
17419        this.get = function (routeId, callback) {
17420            var route = new Post({
17421                slides_files: []
17422            });
17423
17424            if (routeId > 0) {
17425                $http.get(Routing.generate('api_get_post', {post: routeId}))
17426                    .then(function (response) {
17427                        route.update(response.data);
17428
17429                        if (typeof callback == 'function') {
17430                            callback(route);
17431                        }
17432                    }, function errorCallback(response) {
17433                        $log.error(response);
17434                    });
17435            }
17436
17437            return route;
17438        };
17439
17440        function Post(data) {
17441            angular.merge(this, data);
17442
17443            Object.defineProperty(this, 'update', {
17444                enumerable: false,
17445                get: function () {
17446                    return function (data) {
17447                        angular.merge(this, data);
17448                        return this;
17449                    }
17450                }
17451            });
17452
17453            Object.defineProperty(this, 'save', {
17454                enumerable: false,
17455                get: function () {
17456                    return function () {
17457                        var method = this.id ? 'put' : 'post',
17458                            url = this.id ?
17459                                Routing.generate('api_put_post', {post: this.id}) :
17460                                Routing.generate('api_post_post');
17461
17462                        var data = angular.merge({}, this);
17463
17464                        if (angular.isObject(data.rubric) ) {
17465                            data.rubric = data.rubric.id;
17466                        }
17467
17468                        if ( angular.isArray( data.disciplines ) ) {
17469                            data.disciplines = data.disciplines.map(function(discipline) {
17470                                return discipline.id;
17471                            });
17472                        }
17473
17474                        if ( angular.isArray( data.mountain_areas ) ) {
17475                            data.mountain_areas = data.mountain_areas.map(function(mountain_area) {
17476                                return mountain_area.id;
17477                            });
17478                        }
17479
17480                        if ( angular.isArray( data.post_user_qual
17480ification_groups ) ) {
17481                            data.post_user_qualification_groups = data.post_user_qualification_groups.map(function(group) {
17482                                return group.id;
17483                            });
17484                        }
17485
17486                        if ( angular.isObject( data.image ) ) {
17487                            data.image = data.image.id;
17488                        }
17489
17490                        return $http[method](url, data);
17491                    }
17492                }
17493            });
17494        }
17495    }]);
17496
17497},{}],187:[function(require,module,exports){
17498'use strict';
17499
17500angular.module('far.models.camp', [])
17501    .service('Camp', ["$log", "$http", function ($log, $http) {
17502        this.new = function (data) {
17503            return new Camp(data);
17504        };
17505
17506        this.delete = function (route, callback) {
17507            return $http.delete(Routing.generate('api_delete_camp', {camp: route.id}))
17508                .then(function () {
17509                    route = null;
17510
17511                    if (typeof callback == 'function') {
17512                        callback();
17513                    }
17514                }, function errorCallback(response) {
17515                    $log.error(response);
17516                });
17517        };
17518
17519        this.restore = function (route) {
17520            return $http.patch(Routing.generate('api_patch_camp', {id: route.id}))
17521                .then(function () {
17522                    return route = null;
17523                }, function errorCallback(response) {
17524                    $log.error(response);
17525                });
17526        };
17527
17528        this.get = function (routeId, callback) {
17529            var route = new Camp({});
17530
17531            $http.get(Routing.generate('api_get_camp', {camp: routeId}))
17532                .then(function (response) {
17533                    route.update(response.data);
17534
17535                    if (typeof callback == 'function') {
17536                        callback(route);
17537                    }
17538                }, function errorCallback(response) {
17539                    $log.error(response);
17540                });
17541
17542            return route;
17543        };
17544
17545        function Camp(data) {
17546            angular.merge(this, data);
17547
17548            Object.defineProperty(this, 'update', {
17549                enumerable: false,
17550                get: function () {
17551                    return function (data) {
17552                        angular.merge(this, data);
17553
17554                        return this;
17555                    }
17556                }
17557            });
17558
17559            Object.defineProperty(this, 'save', {
17560                enumerable: false,
17561                get: function () {
17562                    return function () {
17563                        var method = this.id ? 'put' : 'post',
17564                            url = this.id ?
17565                                Routing.generate('api_put_camp', {camp: this.id}) :
17566                                Routing.generate('api_post_camp');
17567
17568                        // TODO: Грязный хак
17569                        var data = angular.merge({}, this);
17570
17571                        if ( angular.isObject( data.country ) ) {
17572                            data.country = data.country.id;
17573                        }
17574
17575                        if ( angular.isObject( data.region ) ) {
17576                            data.region = data.region.name;
17577                        }
17578
17579                        if ( angular.isObject( data.image ) ) {
17580                            data.image = data.image.id;
17581                        }
17582
17583                        return $http[method](url, data);
17584                    }
17585                }
17586            });
17587        }
17588    }]);
17589
17590},{}],188:[function(require,module,exports){
17591'use strict';
17592
17593angular.module('far.models.campCountry', [])
17594    .service('campCountry', ["$log", "$http", function ($log, $http) {
17595        var list = [],
17596            firstListQuery = true,
17597            listQueryProgress = false;
17598
17599        Object.defineProperty(this, 'list', {
17600            get: function () {
17601                if (firstListQuery && !listQueryProgress) {
17602                    listQueryProgress = true;
17603
17604                    $http.get(Routing.generate('api_get_camp_country'))
17605                        .then(function (response) {
17606                            response.data.forEach(function (item) {
17607                                list.push(item);
17608                            });
17609
17610                            firstListQuery = false;
17611                            listQueryProgress = false;
17612                        })
17613                        .catch(function (response) {
17614                            $log.error(response);
17615                            listQueryProgress = false;
17616                        });
17617                }
17618
17619                return list;
17620            }
17621        });
17622    }]);
17623
17624},{}],189:[function(require,module,exports){
17625'use strict';
17626
17627angular.module('far.models.campRegion', [])
17628    .service('campRegion', ["$log", "$http", function ($log, $http) {
17629        var list = [],
17630            firstListQuery = true,
17631            listQueryProgress = false;
17632
17633        Object.defineProperty(this, 'list', {
17634            get: function () {
17635                if (firstListQuery && !listQueryProgress) {
17636                    listQueryProgress = true;
17637
17638                    $http.get(Routing.generate('api_camp_region'))
17639                        .then(function (response) {
17640                            response.data.forEach(function (item) {
17641                                list.push(item);
17642                            });
17643
17644                            firstListQuery = false;
17645                            listQueryProgress = false;
17646                        })
17647                        .catch(function (response) {
17648                            $log.error(response);
17649                            listQueryProgress = false;
17650                        });
17651                }
17652
17653                return list;
17654            }
17655        });
17656    }]);
17657
17658},{}],190:[function(require,module,exports){
17659'use strict';
17660
17661angular.module('far.models.club', [])
17662    .service('Club', ["$log", "$http", function ($log, $http) {
17663        this.new = function (data) {
17664            return new Club(data);
17665        };
17666
17667        this.delete = function (route, callback) {
17668            return $http.delete(Routing.generate('api_delete_club', {club: route.id}))
17669                .then(function () {
17670                    route = null;
17671
17672                    if (typeof callback == 'function') {
17673                        callback();
17674                    }
17675                }, function errorCallback(response) {
17676                    $log.error(response);
17677                });
17678        };
17679
17680        this.restore = function (route) {
17681            return $http.patch(Routing.generate('api_patch_club', {id: route.id}))
17682                .then(function () {
17683                    return route = null;
17684                }, function errorCallback(response) {
17685                    $log.error(response);
17686                });
17687        };
17688
17689        this.get = function (routeId, callback) {
17690            var route = new Club({});
17691
17692            $http.get(Routing.generate('api_get_club', {club: routeId}))
17693                .then(function (response) {
17694                    route.update(response.data);
17695
17696                    if (typeof callback == 'function') {
17697                        callback(route);
17698                    }
17699                }, function errorCallback(response) {
17700                    $log.error(response);
17701                });
17702
17703            return route;
17704        };
17705
17706        function Club(data) {
17707            angular.merge(this, data);
17708
17709            Object.defineProperty(this, 'update', {
17710                enumerable: false,
17711                get: function () {
17712                    return function (data) {
17713                        angular.merge(this, data);
17714
17715                        return this;
17716                    }
17717                }
17718            });
17719
17720            Object.defineProperty(this, 'save', {
17721                enumerable: false,
17722                get: function () {
17723                    return function () {
17724                        var method = this.id ? 'put' : 'post',
17725                            url = this.id ?
17726                                Routing.generate('api_put_club', {club: this.id}) :
17727                                Routing.generate('api_post_club');
17728
17729                        // TODO: Грязный хак
17730                        var data = angular.merge({}, this);
17731
17732                        if ( angular.isObject( data.country ) ) {
17733                            data.country = data.country.name;
17734                        }
17735
17736                        if ( angular.isObject( data.region ) ) {
17737                            data.region = data.region.name;
17738                        }
17739
17740                        if ( angular.isObject( data.city ) ) {
17741                            data.city = data.city.name;
17742                        }
17743
17744                        if ( angular.isObject( data.user ) ) {
17745                            data.user = data.user.id;
17746                        }
17747
17748                        if ( angular.isObject( data.avatar ) ) {
17749                            data.avatar = data.avatar.id;
17750                        }
17751
17752                        return $http[method](url, data);
17753                    }
17754                }
17755            });
17756        }
17757    }]);
17758
17759},{}],191:[function(require,module,exports){
17760/**
17761 * Created by Phatbass on 21/02/16.
17762 */
17763
17764'use strict';
17765
17766// TODO: Add all urls
17767angular.module('far.models.committee', [])
17768    .service('Committee', ["$log", "$http", function ($log, $http) {
17769        var list = [],
17770            firstListQuery = true,
17771            listQueryProgress = false;
17772
17773        Object.defineProperty(this, 'list', {
17774            get: function () {
17775                if (firstListQuery && !listQueryProgress) {
17776                    listQueryProgress = true;
17777                    $http.get(Routing.generate('api_committee_get_committees'))
17778                        .then(function (response) {
17779                            response.data.forEach(function (item) {
17780                                item.selected = false;
17781                                list.push(item);
17782                            });
17783
17784                            firstListQuery = false;
17785                            listQueryProgress = false;
17786                        })
17787                        .catch(function (response) {
17788                            $log.error(response);
17789                            listQueryProgress = false;
17790                        });
17791                }
17792
17793                return list;
17794            }
17795        });
17796
17797        this.new = function (data) {
17798            return new Committee(data);
17799        };
17800
17801        this.get = function (routeId, callback) {
17802            var route = new Committee({});
17803
17804            $http.get(Routing.generate('api_committee_get_committee', {committee: routeId}))
17805                .then(function (response) {
17806                    route.update(response.data);
17807
17808                    if (typeof callback == 'function') {
17809                        callback(route);
17810                    }
17811                }, function errorCallback(response) {
17812                    $log.error(response);
17813                });
17814
17815            return route;
17816        };
17817
17818        function Committee(data) {
17819            angular.merge(this, data);
17820
17821            Object.defineProperty(this, 'update', {
17822                enumerable: false,
17823                get: function () {
17824                    return function (data) {
17825                        angular.merge(this, data);
17826
17827                        return this;
17828                    }
17829                }
17830            });
17831
17832            Object.defineProperty(this, 'save', {
17833                enumerable: false,
17834                get: function () {
17835                    return function () {
17836                        var method  = 'put',
17837                            url     = Routing.generate('api_committee_put_committee', {committee: this.id});
17838
17839                        // TODO: Грязный хак
17840                        var data = angular.merge({}, this);
17841
17842                        return $http[method](url, data);
17843                    }
17844                }
17845            });
17846        }
17847
17848    }]);
17849
17850},{}],192:[function(require,module,exports){
17851'use strict';
17852
17853angular.module('far.models.competition.competition', [])
17854    .service('Competition', ["$log", "$http", "usersHelper", function ($log, $http, usersHelper) {
17855        this.new = function (data, userTypes) {
17856            return new Competition(data, userTypes);
17857        };
17858
17859        this.delete = function (route, callback) {
17860            return $http.delete(Routing.generate('api_delete_competition', {competition: route.id}))
17861                .then(function () {
17862                    route = null;
17863
17864                    if (typeof callback == 'function') {
17865                        callback();
17866                    }
17867                }, function errorCallback(response) {
17868                    $log.error(response);
17869                });
17870        };
17871
17872        this.restore = function (route) {
17873            return $http.patch(Routing.generate('api_patch_competition', {id: route.id}))
17874                .then(function () {
17875                    return route = null;
17876                }, function errorCallback(response) {
17877                    $log.error(response);
17878                });
17879        };
17880
17881        this.get = function (routeId, userTypes, callback) {
17882            var route = new Competition({}, userTypes);
17883
17884            $http.get(Routing.generate('api_event_get_event', {id: routeId}))
17885                .then(function (response) {
17886                    if (!response.data.background_image) {
17887                        delete response.data.background_image;
17888                    }
17889
17890                    route.update(response.data);
17891
17892                    route.type = route.type.id;
17893
17894                    route.event_competition.accepted = {id: route.event_competition.accepted};
17895
17896                    if (typeof callback == 'function') {
17897                        callback(route);
17898                    }
17899                }, function errorCallback(response) {
17900                    $log.error(response);
17901                });
17902
17903            return route;
17904        };
17905
17906        function Competition(data, userTypes) {
17907            if (!data.event_competition) {
17908                data.event_competition = {
17909                    users: []
17910                }
17911            }
17912
17913            angular.merge(this, data);
17914
17915            Object.defineProperty(this, 'update', {
17916                enumerable: false,
17917                get: function () {
17918                    return function (data) {
17919                        if (data.event_competition.documents_files) {
17920                            delete this.event_competition.documents_files;
17921                        }
17922
17923                        angular.merge(this, data);
17924
17925                        this.event_competition.updateUsers();
17926
17927                        return this;
17928                    }
17929                }
17930            });
17931
17932            Object.defineProperty(this, 'save', {
17933                enumerable: false,
17934                get: function () {
17935                    return function () {
17936                        var method = this.id ? 'put' : 'post',
17937                            url = this.id ?
17938                                Routing.generate('api_event_put_event', {event: this.id}) :
17939                                Routing.generate('api_event_post_event');
17940
17941                        // Могу преобразовывать data как хочу.
17942                        var data = angular.extend({}, this);
17943
17944                        data.disciplines = [data.disciplines.id];
17945
17946                        data.event_competition.club = data.event_competition.club.id;
17947
17948                        if (angular.isObject(data.camp)) {
17949                            data.camp = data.camp.id;
17950                        }
17951
17952                        if (angular.isObject(data.event_competition.accepted)) {
17953                            data.event_competition.accepted = data.event_competition.accepted.id;
17954                        }
17955
17956                        data.event_competition.event_competition_type = data.event_competition.event_competition_type.map(function (eventCompetitionType) {
17957                            return eventCompetitionType.id;
17958                        });
17959
17960                        data.partners = data.partners.filter(function (partner) {
17961                            return partner.selected;
17962                        }).map(function (partner) {
17963                            return partner.id;
17964                        });
17965
17966                        if (data.background_image && data.background_image.length > 0) {
17967                            data.background_image = data.background_image.filter(function (image) {
17968                                return angular.isDefined(image.serverData)
17969                            }).map(function (image) {
17970                                return image.serverData;
17971                            });
17972
17973                            data.background_image = data.background_image.length > 0 ? data.background_image[0] : undefined;
17974
17975                            data.background_image = data.background_image.id;
17976                        }
17977
17978                        if (data.event_competition.documents_files && data.event_competition.documents_files.length > 0) {
17979                            data.event_competition.documents_files = data.event_competition.documents_files.filter(function (documentFile) {
17980                                return angular.isDefined(documentFile.serverData);
17981                            }).map(function (documentFile) {
17982                                return documentFile.serverData.id;
17983                            });
17984                        }
17985
17986                        return $http[method](url, data);
17987                    }
17988                }
17989            });
17990
17991            usersHelper.initUsers(this.event_competition, userTypes, 'users', 'event_c
17991ompetition_user_type');
17992
17993            this.event_competition.createUser(this.event_competition.userTypes.director);
17994            this.event_competition.createUser(this.event_competition.userTypes.main_judge);
17995        }
17996    }]);
17997
17998},{}],193:[function(require,module,exports){
17999'use strict';
18000
18001angular.module('far.models.competition.competitionReport', [])
18002    .service('CompetitionReport', ["$log", "$http", "usersHelper", function ($log, $http, usersHelper) {
18003        this.new = function (data, userTypes) {
18004            return new Competition(data, userTypes);
18005        };
18006
18007        this.delete = function (route, callback) {
18008            return $http.delete(Routing.generate('api_delete_competition', {competition: route.id}))
18009                .then(function () {
18010                    route = null;
18011
18012                    if (typeof callback == 'function') {
18013                        callback();
18014                    }
18015                }, function errorCallback(response) {
18016                    $log.error(response);
18017                });
18018        };
18019
18020        this.restore = function (route) {
18021            return $http.patch(Routing.generate('api_patch_competition', {id: route.id}))
18022                .then(function () {
18023                    return route = null;
18024                }, function errorCallback(response) {
18025                    $log.error(response);
18026                });
18027        };
18028
18029        this.get = function (routeId, userTypes, callback) {
18030            var route = new Competition({eventReportEdit: 1, eventId: routeId}, userTypes);
18031
18032            $http.get(Routing.generate('api_event_get_event_report', {id: routeId}))
18033                .then(function (response) {
18034                    route.update(response.data);
18035
18036                    if (typeof callback == 'function') {
18037                        callback(route);
18038                    }
18039                }, function errorCallback(response) {
18040                    $log.error(response);
18041                });
18042
18043            return route;
18044        };
18045
18046        function Competition(data, userTypes) {
18047            this.users = [];
18048
18049            angular.merge(this, data);
18050
18051            Object.defineProperty(this, 'update', {
18052                enumerable: false,
18053                get: function () {
18054                    return function (data) {
18055                        if (data.documents_files) {
18056                            delete this.documents_files;
18057                        }
18058
18059                        angular.merge(this, data);
18060
18061                        this.updateUsers();
18062
18063                        return this;
18064                    }
18065                }
18066            });
18067
18068            Object.defineProperty(this, 'save', {
18069                enumerable: false,
18070                get: function () {
18071                    return function () {
18072                        var method = this.eventReportEdit ? 'put' : 'post',
18073                            url = this.eventReportEdit ?
18074                                Routing.generate('api_event_put_event_report', {id: this.eventId}) :
18075                                Routing.generate('api_event_post_event_report');
18076
18077                        // Могу преобразовывать data как хочу.
18078                        var data = angular.extend({}, this);
18079
18080                        if (data.documents_files && data.documents_files.length > 0) {
18081                            data.documents_files = data.documents_files.filter(function (documentFile) {
18082                                return angular.isDefined(documentFile.serverData);
18083                            }).map(function (documentFile) {
18084                                return documentFile.serverData.id;
18085                            });
18086                        }
18087
18088                        return $http[method](url, data);
18089                    }
18090                }
18091            });
18092
18093            usersHelper.initUsers(this, userTypes, 'users', 'event_competition_user_type');
18094
18095            this.createUser(this.userTypes.safety);
18096            this.createUser(this.userTypes.judge);
18097        }
18098    }]);
18099
18100},{}],194:[function(require,module,exports){
18101'use strict';
18102
18103angular.module('far.models.competition.competitionType', [])
18104    .service('CompetitionType', ["$log", "$http", function ($log, $http) {
18105        var list = {},
18106            firstListQuery = true,
18107            listQueryProgress = false;
18108
18109        Object.defineProperty(this, 'list', {
18110            get: function () {
18111                if (firstListQuery && !listQueryProgress) {
18112                    listQueryProgress = true;
18113                    $http.get(Routing.generate('api_get_competition_type'))
18114                        .then(function (response) {
18115                            list = angular.merge(list, response.data);
18116
18117                            listQueryProgress = false;
18118                            firstListQuery = false;
18119                        }, function errorCallback(response) {
18120                            listQueryProgress = false;
18121                            $log.error(response);
18122                        });
18123                }
18124
18125                return list;
18126            }
18127        });
18128    }]);
18129
18130},{}],195:[function(require,module,exports){
18131'use strict';
18132
18133angular.module('far.models.competition.competitionUserType', [])
18134    .service('CompetitionUserType', ["$log", "$http", "$q", function ($log, $http, $q) {
18135        var list = {},
18136            firstListQuery = true,
18137            listQueryProgress = false;
18138
18139        Object.defineProperty(this, 'list', {
18140            get: function () {
18141                if (firstListQuery && !listQueryProgress) {
18142                    listQueryProgress = true;
18143                    $http.get(Routing.generate('api_get_competition_user_type'))
18144                        .then(function (response) {
18145                            list = angular.merge(list, response.data);
18146
18147                            listQueryProgress = false;
18148                            firstListQuery = false;
18149                        }, function errorCallback(response) {
18150                            listQueryProgress = false;
18151                            $log.error(response);
18152                        });
18153                }
18154
18155                return $q(function (resolve) {
18156                    resolve(list);
18157                });
18158            }
18159        });
18160    }]);
18161
18162},{}],196:[function(require,module,exports){
18163/**
18164 * Created by Phatbass on 21/02/16.
18165 */
18166
18167'use strict';
18168
18169// TODO: Add all urls
18170angular.module('far.models.discipline', [])
18171    .service('Discipline', ["$log", "$http", function ($log, $http) {
18172        var list = [],
18173            firstListQuery = true,
18174            listQueryProgress = false;
18175
18176        Object.defineProperty(this, 'list', {
18177            get: function () {
18178                if (firstListQuery && !listQueryProgress) {
18179                    listQueryProgress = true;
18180                    $http.get(Routing.generate('api_discipline_get_disciplines'))
18181                        .then(function (response) {
18182                            response.data.forEach(function (item) {
18183                                item.selected = false;
18184                                list.push(item);
18185                            });
18186
18187                            firstListQuery = false;
18188                            listQueryProgress = false;
18189                        })
18190                        .catch(function (response) {
18191                            $log.error(response);
18192                            listQueryProgress = false;
18193                        });
18194                }
18195
18196                return list;
18197            }
18198        });
18199
18200        var events = [];
18201
18202        Object.defineProperty(this, 'events', {
18203            get: function () {
18204                $http.get(Routing.generate('api_discipline_get_discipline_events', {discipline: discipline}))
18205                    .then(function (response) {
18206                        angular.forEach(response.data, function (events) {
18207                            vm.data.push(events);
18208                        });
18209                    }, function errorCallback(response) {
18210                        $log.error(response);
18211                        showModalMessage('Невозможно загрузить мероприятия.');
18212                    });
18213
18214                return list;
18215            }
18216        });
18217    }]);
18218
18219},{}],197:[function(require,module,exports){
18220/**
18221 * Created by Phatbass on 21/02/16.
18222 */
18223
18224'use strict';
18225
18226// TODO: Add all urls
18227angular.module('far.models.rank', [])
18228    .service('Rank', ["$log", "$http", function ($log, $http) {
18229        this.get = function (data, callback) {
18230            var model = new Rank(data);
18231
18232            $http.get(Routing.generate('api_discipline_get_discipline_rank', data))
18233                .then(function (response) {
18234                    response.data.season = response.data.season.id.toString();
18235
18236                    response.data.people_xerox = +response.data.people_xerox;
18237                    response.data.people_xerox = response.data.people_xerox.toString();
18238
18239                    if (angular.isObject(response.data.class)) {
18240                        response.data.class = response.data.class.id.toString();
18241                    }
18242
18243                    if (angular.isObject(response.data.type)) {
18244                        response.data.type = response.data.type.id.toString();
18245                    }
18246
18247                    model.update(response.data);
18248
18249                    if (typeof callback == 'function') {
18250                        callback(model);
18251                    }
18252                }, function (response) {
18253                    $log.error(response);
18254                });
18255
18256            return model;
18257        };
18258
18259        function Rank(data) {
18260            angular.merge(this, data);
18261
18262            Object.defineProperty(this, 'update', {
18263                enumerable: false,
18264                get: function () {
18265                    return function (data) {
18266                        angular.merge(this, data);
18267
18268                        return this;
18269                    }
18270                }
18271            });
18272
18273            Object.defineProperty(this, 'save', {
18274                enumerable: false,
18275                get: function () {
18276                    return function () {
18277                        var method = this.id ? 'put' : 'post',
18278                            url = this.id ?
18279                                Routing.generate('api_discipline_put_discipline_rank', {rank: this.id}) :
18280                                Routing.generate('api_discipline_post_discipline_rank');
18281
18282                        var data = angular.merge({}, this);
18283
18284                        data.people_xerox = Boolean(parseInt(data.people_xerox));
18285
18286                        data.values = data.values.filter(function (value) {
18287                            if (value.age && value.city && value.name && value.points) {
18288                                return true;
18289                            }
18290                        });
18291
18292                        return $http[method](url, data);
18293                    }
18294                }
18295            });
18296        }
18297    }]);
18298
18299},{}],198:[function(require,module,exports){
18300/**
18301 * Created by Phatbass on 21/02/16.
18302 */
18303
18304'use strict';
18305
18306// TODO: Add all urls
18307angular.module('far.models.rankSeason', [])
18308    .service('RankSeason', ["$log", "$http", function ($log, $http) {
18309        var list = [];
18310
18311        Object.defineProperty(this, 'list', {
18312            get: function () {
18313                list = [];
18314
18315                $http.get(Routing.generate('api_discipline_get_discipline_rank_seasons'))
18316                    .then(function (response) {
18317                        response.data.forEach(function (item, index) {
18318                            if (index == 0) {
18319                                item.selected = true;
18320                            } else {
18321                                item.selected = false;
18322                            }
18323
18324                            list.push(item);
18325                        });
18326                    }, function (response) {
18327                        $log.error(response);
18328                    });
18329
18330                return list;
18331            }
18332        });
18333
18334        this.new = function (data) {
18335            return new RankSeason(data);
18336        };
18337
18338        function RankSeason(data) {
18339            angular.merge(this, data);
18340
18341            Object.defineProperty(this, 'save', {
18342                enumerable: false,
18343                get: function () {
18344                    return function () {
18345                        var method = 'post',
18346                            url = Routing.generate('api_discipline_post_discipline_rank_season');
18347
18348                        var data = angular.merge({}, this);
18349
18350                        return $http[method](url, data);
18351                    }
18352                }
18353            });
18354        }
18355    }]);
18356
18357},{}],199:[function(require,module,exports){
18358'use strict';
18359
18360angular.module('far.models.document', [])
18361    .service('Document', ["$log", "$http", function ($log, $http) {
18362        var types = [],
18363            typeComplete = false,
18364            kinds = [],
18365            kindComplete = false,
18366            committees = [],
18367            committeeComplete = false,
18368            new_committees = [],
18369            new_committeesComplete = false,
18370            years = [],
18371            yearComplete = false;
18372
18373        Object.defineProperty(this, 'types', {
18374            get: function () {
18375                if (!typeComplete) {
18376                    typeComplete = true;
18377
18378                    $http.get(Routing.generate('api_get_document_type'))
18379                        .then(function (response) {
18380                            response.data.forEach(function (routeData) {
18381                                types.push(routeData);
18382                            });
18383                        }, function errorCallback(response) {
18384                            $log.error(response);
18385                        });
18386                }
18387
18388                return types;
18389            }
18390        });
18391
18392        Object.defineProperty(this, 'kinds', {
18393            get: function () {
18394                if (!kindComplete) {
18395                    kindComplete = true;
18396
18397                    $http.get(Routing.generate('api_get_document_kind'))
18398                        .then(function (response) {
18399                            response.data.forEach(function (routeData) {
18400                                kinds.push(routeData);
18401                            });
18402
18403                        }, function errorCallback(response) {
18404                            $log.error(response);
18405                        });
18406                }
18407
18408                return kinds;
18409            }
18410        });
18411
18412        Object.defineProperty(this, 'committees', {
18413            get: function () {
18414                if (!committeeComplete) {
18415                    committeeComplete = true;
18416
18417                    $http.get(Routing.generate('api_get_document_committee'))
18418                        .then(function (response) {
18419                            response.data.forEach(function (routeData) {
18420                                committees.push(routeData);
18421                            });
18422                        }, function errorCallback(response) {
18423                            $log.error(response);
18424                        });
18425                }
18426
18427                return committees;
18428            }
18429        });
18430
18431
18432        Object.defineProperty(this, 'new_committees', {
18433            get: function () {
18434                if (!new_committeesComplete) {
18435                    new_committeesComplete = true;
18436
18437                    $http.get(Routing.generate('api_committee_get_committees'))
18438                        .then(function (response) {
18439                            response.data.forEach(function (routeData) {
18440                                new_committees.push(routeData);
18441                            });
18442                        }, function errorCallback(response) {
18443                            $log.error(response);
18444                        });
18445                }
18446
18447                return new_committees;
18448            }
18449        });
18450
18451        Object.defineProperty(this, 'years', {
18452            get: function () {
18453                if (!yearComplete) {
18454                    yearComplete = true;
18455
18456                    $http.get(Routing.generate('api_get_document_year'))
18457                        .then(function (response) {
18458                            response.data.forEach(function (routeData) {
18459                                years.push(routeData);
18460                            });
18461                        }, function errorCallback(response) {
18462                            $log.error(response);
18463                        });
18464                }
18465
18466                return years;
18467            }
18468        });
18469
18470        this.new = function (data) {
18471            return new Document(data);
18472        };
18473
18474        this.delete = function (route, callback) {
18475            return $http.delete(Routing.generate('api_delete_document', {document: route.id}))
18476                .then(function () {
18477                    route = null;
18478
18479                    if (typeof callback == 'function') {
18480                        callback();
18481                    }
18482                }, function errorCallback(response) {
18483                    $log.error(response);
18484                });
18485        };
18486
18487        this.restore = function (route) {
18488            return $http.patch(Routing.generate('api_patch_document', {id: route.id}))
18489                .then(function () {
18490                    return route = null;
18491                }, function errorCallback(response) {
18492                    $log.error(response);
18493                });
18494        };
18495
18496        this.get = function (id, callback) {
18497            var route = new Document({});
18498
18499            $http.get(Routing.generate('api_get_document', {document: id}))
18500                .then(function (response) {
18501                    route.update(response.data);
18502
18503                    if (typeof callback == 'function') {
18504                        callback();
18505                    }
18506                }, function errorCallback(response) {
18507                    $log.error(response);
18508                });
18509
18510            return route;
18511        };
18512
18513        function Document(data) {
18514            angular.merge(this, data);
18515
18516            Object.defineProperty(this, 'update', {
18517                enumerable: false,
18518                get: function () {
18519                    return function (data) {
18520                        angular.merge(this, data);
18521
18522                        return this;
18523                    }
18524                }
18525            });
18526
18527            Object.defineProperty(this, 'save', {
18528                enumerable: false,
18529                get: function () {
18530                    return function () {
18531                        var method = this.id ? 'put' : 'post',
18532                            url = this.id ?
18533                                Routing.generate('api_put_document', {document: this.id}) :
18534                                Routing.generate('api_post_document');
18535
18536                        // TODO: Грязный хак
18537                        var data = angular.merge({}, this);
18538
18539                        var objectToId = [
18540                            'disciplines',
18541                            'types',
18542                            'kinds',
18543                            'committees',
18544                            'new_committees',
18545                        ];
18546
18547                        for (var key in objectToId) {
18548                            var dataName = objectToId[key];
18549
18550                            data[dataName] = data[dataName].map(function (value) {
18551                                return value.id;
18552                            });
18553                        }
18554
18555                        if (data.hasOwnProperty('file')) {
18556                            data['file'] = data['file'].id;
18557                        }
18558
18559                        return $http[method](url, data);
18560                    }
18561                }
18562            });
18563        }
18564    }]);
18565
18566},{}],200:[function(require,module,exports){
18567'use strict';
18568
18569require('./educationStatus');
18570require('./educationDiscipline');
18571require('./educationQualificationGroup');
18572require('../partners/partners');
18573require('../../helpers/users/users.module');
18574
18575angular.module('far.models.education.education', [
18576        'far.models.education.status',
18577        'far.models.partners',
18578        'far.models.education.userType',
18579        'far.models.education.discipline',
18580        'far.helpers.users'
18581    ])
18582    .service('education', ["$log", "$rootScope", "$http", "educationStatus", "educationQualificationGroup", "educationDiscipline", "partners", "usersHelper", function ($log, $rootScope, $http, educationStatus, educationQualificationGroup, educationDiscipline, partners, usersHelper) {
18583        this.new = function (eventData, userTypes) {
18584            return new Education(eventData, userTypes);
18585        };
18586
18587        this.get = function (eventId, userTypes, callback) {
18588            var event = new Education({}, userTypes);
18589
18590            $http.get(Routing.generate('api_event_get_event', {id: eventId}))
18591                .then(function (response) {
18592                    if (!response.data.background_image) {
18593                        delete response.data.background_image;
18594                    }
18595
18596                    event.update(response.data);
18597
18598                    event.type = event.type.id;
18599
18600                    event.event_education.accepted = {id: event.event_education.accepted};
18601
18602                    event.event_education.participants = {
18603                        min: event.event_education.participants_count_from,
18604                        max: event.event_education.participants_count_to
18605                    };
18606
18607                    var partnersWatch = $rootScope.$watch(function () {
18608                        return partners.list.length;
18609                    }, function (length) {
18610                        if (length > 0) {
18611                            var event_partners_length = event.partners.length;
18612
18613                            if (event_partners_length) {
18614                                partners.list.forEach(function (partner) {
18615                                    if (length == event_partners_length) {
18616                                        partner.selected = true;
18617                                    } else {
18618                                        event.partners.forEach(function (selectedPartner) {
18619                                            if (partner.id == selectedPartner.id) {
18620                                                partner.selected = true;
18621                                            }
18622                                        });
18623                                    }
18624                                });
18625
18626                                partnersWatch();
18627                            }
18628                        }
18629                    });
18630
18631                    if (typeof callback == 'function') {
18632                        callback(event);
18633                    }
18634                })
18635                .catch(function (response) {
18636                    $log.error(response);
18637                });
18638
18639            return event;
18640        };
18641
18642        function Education(eventData, userTypes) {
18643            if (!eventData.event_education) {
18644                eventData.event_education = {
18645                    documents: {},
18646                    users: [],
18647                    users_complite: [],
18648                    participants: {
18649                        min: 1,
18650                        max: 500
18651                    }
18652                }
18653            }
18654
18655            angular.merge(this, eventData);
18656
18657            Object.defineProperty(this, 'update', {
18658                enumerable: false,
18659                get: function () {
18660                    return function (eventData) {
18661                        if (eventData.event_education.documents_files) {
18662                            delete this.event_education.documents_files;
18663                        }
18664
18665                        /*
18666                        fix AFFEB-11 После пересохранения любого ранее созданного меропрития, участники
18667                        
18668                        var users = this.event_education.users;
18669
18670                        users.forEach(function (u, index) {
18671                            eventData.event_education.users.forEach(function (ud) {
18672                                if (ud.event_education_user_type.system_name === u.event_education_user_type.system_name) {
18673                                    users[index] = ud;
18674                                }
18675                            });
18676                        });
18677
18678                        eventData.event_education.users = users; */
18679
18680                        angular.merge(this, eventData);
18681
18682                        this.event_education.updateUsers();
18683                    }
18684                }
18685            });
18686
18687            Object.defineProperty(this, 'save', {
18688                enumerable: false,
18689                get: function () {
18690                    return function () {
18691                        var method = this.id ? 'put' : 'post',
18692                            url = this.id ?
18693                                Routing.generate('api_event_put_event', {event: this.id}) :
18694                                Routing.generate('api_event_post_event');
18695
18696                        // Могу преобразовывать data как хочу.
18697                        var data = angular.extend({}, this);
18698
18699                        if (angular.isObject(data.event_education.accepted)) {
18700                            data.event_education.accepted = data.event_education.accepted.id;
18701                        }
18702
18703                        if (angular.isObject(data.event_education.club)) {
18704                            data.event_education.club = data.event_education.club.id;
18705                        }
18706
18707                        if (angular.isObject(data.camp)) {
18708                            data.camp = data.camp.id;
18709                        }
18710
18711                        data.event_education.participants_count_from = data.event_education.participants.min;
18712                        data.event_education.participants_count_to = data.event_education.participants.max;
18713
18714                        delete data.event_education.participants;
18715
18716                        data.partners = data.partners.filter(function (partner) {
18717                            return partner.selected;
18718                        }).map(function (partner) {
18719                            return partner.id;
18720                        });
18721
18722                        if (data.background_image && data.background_image.length > 0) {
18723                            data.background_image = data.background_image.filter(function (image) {
18724                                return angular.isDefined(image.serverData)
18725                            }).map(function (image) {
18726                                return image.serverData;
18727                            });
18728
18729                            data.background_image = data.background_image.length > 0 ? data.background_image[0].id : undefined;
18730                        }
18731
18732                        if (data.event_education.documents_files && data.event_education.documents_files.length > 0) {
18733                            data.event_education.documents_files = data.event_education.documents_files.filter(function (documentFile) {
18734                                return angular.isDefined(documentFile.serverData);
18735                            }).map(function (documentFile) {
18736                                return documentFile.serverData.id;
18737                            });
18738                        }
18739
18740                        data.event_education.users = data.event_education.users.filter(function (value) {
18741                            return angular.isObject(value.user);
18742                        });
18743
18744                        data.event_education.documents = Object.keys(data.event_education.documents).map(function (key) { return data.event_education.documents[key].id; });
18745
18746                        return $http[method](url, data);
18747                    }
18748                }
18749            });
18750
18751            usersHelper.initUsers(this.event_education, userTypes, 'users', 'event_education_user_type');
18752
18753            this.event_education.createUser(this.event_education.userTypes.user_safety);
18754            this.event_education.createUser(this.event_education.userTypes.user_coach);
18755            this.event_education.createUser(this.event_education.userTypes.user_chief);
18756
18757
18758        }
18759    }]);
18760
18761},{"../../helpers/users/users.module":169,"../partners/partners":222,"./educationDiscipline":201,"./educationQualificationGroup":202,"./educationStatus":204}],201:[function(require,module,exports){
18762'use strict';
18763
18764angular.module('far.models.education.discipline', [])
18765	.service('educationDiscipline', ["$log", "$http", function($log, $http) {
18766		var list = [],
18767			firstListQuery = true,
18768			listQueryProgress = false;
18769
18770		Object.defineProperty(this, 'list', {
18771			get: function () {
18772				if (firstListQuery && !listQueryProgress) {
18773					listQueryProgress = true;
18774					$http.get(Routing.generate('api_discipline_get_disciplines'))
18775						.then(function(response) {
18776							response.data.forEach(function(item) {
18777								item.selected = false;
18778								list.push(item);
18779							});
18780
18781							firstListQuery = false;
18782							listQueryProgress = false;
18783						})
18784						.catch(function(response) {
18785							$log.error(response);
18786							listQueryProgress = false;
18787						});
18788				}
18789
18790				return list;
18791			}
18792		});
18793	}]);
18794
18795},{}],202:[function(require,module,exports){
18796'use strict';
18797
18798angular.module('far.models.education.userType', [])
18799	.service('educationQualificationGroup', ["$log", "$http", function($log, $http) {
18800		var list = [],
18801			firstListQuery = true,
18802			listQueryProgress = false;
18803
18804		Object.defineProperty(this, 'list', {
18805			get: function() {
18806				if (firstListQuery && !listQueryProgress) {
18807					listQueryProgress = true;
18808					$http.get(Routing.generate('api_get_user_qualificationgroups'))
18809						.then(function(response) {
18810							response.data.forEach(function(item) {
18811								item.selected = false;
18812								item.select_all = false;
18813								list.push(item);
18814							});
18815
18816							listQueryProgress = false;
18817							firstListQuery = false;
18818						})
18819						.catch(function(response) {
18820							listQueryProgress = false;
18821							$log.error(response);
18822						});
18823
18824					list.push({
18825						id: 0,
18826						name: 'Все желающие',
18827						selected: false,
18828						select_all: true
18829					});
18830				}
18831
18832				return list;
18833			}
18834		});
18835	}]);
18836
18837},{}],203:[function(require,module,exports){
18838'use strict';
18839
18840require('../../helpers/users/users.module');
18841
18842angular.module('far.models.education.educationReport', ['far.helpers.users'])
18843    .service('educationReport', ["$log", "$http", "usersHelper", function ($log, $http, usersHelper) {
18844        this.new = function (eventReportData, userTypes) {
18845            eventReportData.eventReportEdit = 0;
18846
18847            return new EducationReport(eventReportData, userTypes);
18848        };
18849
18850        this.get = function (eventId, userTypes, callback) {
18851            var eventReport = new EducationReport({eventReportEdit: 1}, userTypes);
18852
18853            $http.get(Routing.generate('api_event_get_event_report', {id: eventId}))
18854                .then(function (response) {
18855                    eventReport.update(response.data);
18856
18857                    if (typeof callback == 'function') {
18858                        callback(eventReport);
18859                    }
18860                })
18861                .catch(function (response) {
18862                    $log.error(response);
18863                });
18864
18865            return eventReport;
18866        };
18867
18868        function EducationReport(eventData, userTypes) {
18869            if (!eventData.users) {
18870                eventData.users = [];
18871            }
18872
18873            angular.merge(this, eventData);
18874
18875            Object.defineProperty(this, 'update', {
18876                enumerable: false,
18877                get: function () {
18878                    return function (eventData) {
18879                        if (eventData.documents_files) {
18880                            delete this.documents_files;
18881                        }
18882
18883                        angular.merge(this, eventData);
18884
18885                        this.updateUsers();
18886
18887                        this.ascents.forEach(function (ascent) {
18888                            ascent.users = [];
18889
18890                            if (angular.isArray(ascent.ascent_users)) {
18891                                ascent.ascent_users.forEach(function (user) {
18892                                    if (user.ascent_user_type_id.system_name === 'chief') {
18893                                        ascent.user_chief = user.user;
18894                                    } else if (user.ascent_user_type_id.system_name === 'instructor') {
18895                                        ascent.instructor = user.user;
18896                                    } else {
18897                                        ascent.users.push(user.user);
18898                                    }
18899                                })
18900                            }
18901                        });
18902
18903                        return this;
18904                    }
18905                }
18906            });
18907
18908            Object.defineProperty(this, 'save', {
18909                enumerable: false,
18910                get: function () {
18911                    return function () {
18912                        var method = this.eventReportEdit ? 'put' : 'post',
18913                            url = this.eventReportEdit ?
18914                                Routing.generate('api_event_put_event_report', {id: this.event.id}) :
18915                                Routing.generate('api_event_post_event_report');
18916
18917                        // Могу преобразовывать data как хочу.
18918                        var data = angular.extend({}, this);
18919
18920                        if (data.documents_files && data.documents_files.length > 0) {
18921                            data.documents_files = data.documents_files.filter(function (documentFile) {
18922                                return angular.isDefined(documentFile.serverData);
18923                            }).map(function (documentFile) {
18924                                return documentFile.serverData.id;
18925                            });
18926                        }
18927
18928
18929                        data.ascents = data.ascents.map(function (ascent) {
18930                            var users = [];
18931
18932                            if (ascent.user_chief) {
18933                                users.push({
18934                                    user: ascent.user_chief.id,
18935                                    ascent_user_type_id: data.ascent_user_types.chief.id
18936                                });
18937                            }
18938
18939                            if (ascent.instructor) {
18940                                users.push({
18941                                    user: ascent.instructor.id,
18942                                    ascent_user_type_id: data.ascent_user_types.instructor.id
18943                                });
18944                            }
18945
18946                            ascent.users.forEach(function (user) {
18947                                users.push({
18948                                    user: {
18949                                        email: user.email,
18950                                        fio: user.fio
18951                                    },
18952                                    ascent_user_type_id: data.ascent_user_types.participant.id
18953                                })
18954                            });
18955
18956                            ascent.ascent_users = users;
18957                            ascent.ascent_mountain_route = ascent.ascent_mountain_route.id;
18958                            ascent.ascent_type = ascent.ascent_type ? ascent.ascent_type.id : null;
18959
18960                            delete(ascent.users);
18961                            delete(ascent.user_chief);
18962
18963                            return ascent;
18964                        });
18965
18966                        var users_complite = [];
18967
18968                        data.users_complite.forEach(function (user) {
18969
18970                            /*if ('user' in user) {
18971                                users_complite.push({user : user.user, event_education_user_type: 4})
18972                            } else {
18973                                users_complite.push({
18974                                    user: {
18975                                        email: user.email,
18976                                        fio: user.fio
18977                                    },
18978                                    event_education_user_type: 4 // Участник
18979                                })
18980                            }*/
18981
18982                            users_complite.push({
18983                                user: {
18984                                    email: user.email,
18985                                    fio: user.fio
18986                                },
18987                                event_education_user_type: 4 // Участник
18988                            })
18989                        });
18990
18991                        data.users_complite = users_complite;
18992
18993                        delete(data.ascent_user_types);
18994                        delete(data.eventUserTypes);
18995
18996                        return $http[method](url, data);
18997                    }
18998                }
18999            });
19000
19001            usersHelper.initUsers(this, userTypes, 'users', 'event_education_user_type');
19002        }
19003    }]);
19004
19005},{"../../helpers/users/users.module":169}],204:[function(require,module,exports){
19006'use strict';
19007
19008angular.module('far.models.education.status', [])
19009    .service('educationStatus', function () {
19010        var list = [{
19011            id: false,
19012            status: 'Черновик'
19013        }, {
19014            id: true,
19015            status: 'Одобрено'
19016        }];
19017
19018        Object.defineProperty(this, 'list', {
19019            get: function () {
19020                return list;
19021            }
19022        });
19023    });
19024
19025},{}],205:[function(require,module,exports){
19026'use strict';
19027
19028require('./eventStatus');
19029require('./eventDiscipline');
19030require('./eventQualificationGroup');
19031require('../partners/partners');
19032require('../../helpers/users/users.module');
19033
19034angular.module('far.models.event.event', [
19035        'far.models.event.status',
19036        'far.models.partners',
19037        'far.models.event.userType',
19038        'far.models.event.discipline',
19039        'far.helpers.users'
19040    ])
19041    .service('event', ["$log", "$rootScope", "$http", "eventStatus", "eventQualificationGroup", "eventDiscipline", "partners", "usersHelper", function ($log, $rootScope, $http, eventStatus, eventQualificationGroup, eventDiscipline, partners, usersHelper) {
19042        this.new = function (eventData, userTypes) {
19043            return new Event(eventData, userTypes);
19044        };
19045
19046        this.get = function (eventId, userTypes, callback) {
19047            var event = new Event({}, userTypes);
19048
19049            $http.get(Routing.generate('api_event_get_event', {id: eventId}))
19050                .then(function (response) {
19051                    if (!response.data.background_image) {
19052                        delete response.data.background_image;
19053                    }
19054
19055                    event.update(response.data);
19056
19057                    event.type = event.type.id;
19058
19059                    event.event_application.accepted = {id: event.event_application.accepted};
19060
19061                    event.event_application.participants = {
19062                        min: event.event_application.participants_count_from,
19063                        max: event.event_application.participants_count_to
19064                    };
19065                   
19066                    console.log(event.revisor_id);
19067
19068                    var partnersWatch = $rootScope.$watch(function () {
19069                        return partners.list.length;
19070                    }, function (length) {
19071                        if (length > 0) {
19072                            var event_partners_length = event.partners.length;
19073
19074                            if (event_partners_length) {
19075                                partners.list.forEach(function (partner) {
19076                                    if (length == event_partners_length) {
19077                                        partner.selected = true;
19078                                    } else {
19079                                        event.partners.forEach(function (selectedPartner) {
19080                                            if (partner.id == selectedPartner.id) {
19081                                                partner.selected = true;
19082                                            }
19083                                        });
19084                                    }
19085                                });
19086
19087                                partnersWatch();
19088                            }
19089                        }
19090                    });
19091
19092                    if (typeof callback == 'function') {
19093                        callback(event);
19094                    }
19095                })
19096                .catch(function (response) {
19097                    $log.error(response);
19098                });
19099
19100            return event;
19101        };
19102
19103        function Event(eventData, userTypes) {
19104            if (!eventData.event_application) {
19105                eventData.event_application = {
19106                    documents: {},
19107                    users: [],
19108                    participants: {
19109                        min: 1,
19110                        max: 500
19111                    }
19112                }
19113            }
19114
19115            angular.merge(this, eventData);
19116
19117            Object.defineProperty(this, 'update', {
19118                enumerable: false,
19119                get: function () {
19120                    return function (eventData) {
19121                        if (eventData.event_application.documents_files) {
19122                            delete this.event_application.documents_files;
19123                        }
19124
19125                        angular.merge(this, eventData);
19126
19127                        this.event_application.updateUsers();
19128                    }
19129                }
19130            });
19131
19132            Object.defineProperty(this, 'save', {
19133                enumerable: false,
19134                get: function () {
19135                    return function () {
19136                        var method = this.id ? 'put' : 'post',
19137                            url = this.id ?
19138                                Routing.generate('api_event_put_event', {event: this.id}) :
19139                                Routing.generate('api_event_post_event');
19140
19141                        // Могу преобразовывать data как хочу.
19142                        var data = angular.extend({}, this);
19143
19144                        if (angular.isObject(data.event_application.accepted)) {
19145                            data.event_application.accepted = data.event_application.accepted.id;
19146                        }
19147
19148                        if (angular.isObject(data.event_application.club)) {
19149                            data.event_application.club = data.event_application.club.id;
19150                        }
19151
19152                        if (angular.isObject(data.camp)) {
19153                            data.camp = data.camp.id;
19154                        }
19155
19156                        data.event_application.participants_count_from = data.event_application.participants.min;
19157                        data.event_application.participants_count_to = data.event_application.participants.max;
19158
19159                        delete data.event_application.participants;
19160
19161                        data.partners = data.partners.filter(function (partner) {
19162                            return partner.selected;
19163                        }).map(function (partner) {
19164                            return partner.id;
19165                        });
19166
19167                        if (data.background_image && data.background_image.length > 0) {
19168                            data.background_image = data.background_image.filter(function (image) {
19169                                return angular.isDefined(image.serverData)
19170                            }).map(function (image) {
19171                                return image.serverData;
19172                            });
19173
19174                            data.background_image = data.background_image.length > 0 ? data.background_image[0].id : undefined;
19175                        }
19176
19177                        if (data.event_application.documents_files && data.event_application.documents_files.length > 0) {
19178                            data.event_application.documents_files = data.event_application.documents_files.filter(function (documentFile) {
19179                                return angular.isDefined(documentFile.serverData);
19180                            }).map(function (documentFile) {
19181                                return documentFile.serverData.id;
19182                            });
19183                        }
19184
19185                        data.event_application.users = data.event_application.users.filter(function (value) {
19186                            return angular.isObject(value.user);
19187                        });
19188
19189                        data.event_application.documents = Object.keys(data.event_application.documents).map(function (key) { return data.event_application.documents[key].id; });
19190
19191                        return $http[method](url, data);
19192                    }
19193                }
19194            });
19195
19196            usersHelper.initUsers(this.event_application, userTypes, 'users', 'event_application_user_type');
19197
19198            this.event_application.createUser(this.event_application.userTypes.user_chief);
19199            this.event_application.createUser(this.event_application.userTypes.user_coach);
19200            this.event_application.createUser(this.event_application.userTypes.user_safety);
19201        }
19202    }]);
19203
19204},{"../../helpers/users/users.module":169,"../partners/partners":222,"./eventDiscipline":206,"./eventQualificationGroup":207,"./eventStatus":210}],206:[function(require,module,exports){
19205'use strict';
19206
19207angular.module('far.models.event.discipline', [])
19208	.service('eventDiscipline', ["$log", "$http", function($log, $http) {
19209		var list = [],
19210			firstListQuery = true,
19211			listQueryProgress = false;
19212
19213		Object.defineProperty(this, 'list', {
19214			get: function () {
19215				if (firstListQuery && !listQueryProgress) {
19216					listQueryProgress = true;
19217					$http.get(Routing.generate('api_discipline_get_disciplines'))
19218						.then(function(response) {
19219							response.data.forEach(function(item) {
19220								item.selected = false;
19221								list.push(item);
19222							});
19223
19224							firstListQuery = false;
19225							listQueryProgress = false;
19226						})
19227						.catch(function(response) {
19228							$log.error(response);
19229							listQueryProgress = false;
19230						});
19231				}
19232
19233				return list;
19234			}
19235		});
19236	}]);
19237
19238},{}],207:[function(require,module,exports){
19239'use strict';
19240
19241angular.module('far.models.event.userType', [])
19242	.service('eventQualificationGroup', ["$log", "$http", function($log, $http) {
19243		var list = [],
19244			firstListQuery = true,
19245			listQueryProgress = false;
19246
19247		Object.defineProperty(this, 'list', {
19248			get: function() {
19249				if (firstListQuery && !listQueryProgress) {
19250					listQueryProgress = true;
19251					$http.get(Routing.generate('api_get_user_qualificationgroups'))
19252						.then(function(response) {
19253							response.data.forEach(function(item) {
19254								item.selected = false;
19255								item.select_all = false;
19256								list.push(item);
19257							});
19258
19259							listQueryProgress = false;
19260							firstListQuery = false;
19261						})
19262						.catch(function(response) {
19263							listQueryProgress = false;
19264							$log.error(response);
19265						});
19266
19267					list.push({
19268						id: 0,
19269						name: 'Все желающие',
19270						selected: false,
19271						select_all: true
19272					});
19273				}
19274
19275				return list;
19276			}
19277		});
19278	}]);
19279
19280},{}],208:[function(require,module,exports){
19281'use strict';
19282
19283angular.module('far.models.event.regions', [])
19284	.service('eventRegions', ["$log", "$http", function($log, $http) {
19285		var list = [],
19286			firstListQuery = true,
19287			listQueryProgress = false;
19288
19289		Object.defineProperty(this, 'list', {
19290			get: function () {
19291				if (firstListQuery && !listQueryProgress) {
19292					listQueryProgress = true;
19293					$http.get(Routing.generate('api_event_get_regions'))
19294						.then(function(response) {
19295							response.data.forEach(function(item) {
19296								item.selected = false;
19297								list.push(item);
19298							});
19299
19300							firstListQuery = false;
19301							listQueryProgress = false;
19302						})
19303						.catch(function(response) {
19304							$log.error(response);
19305							listQueryProgress = false;
19306						});
19307				}
19308
19309				return list;
19310			}
19311		});
19312	}]);
19313
19314},{}],209:[function(require,module,exports){
19315'use strict';
19316
19317require('../../helpers/users/users.module');
19318
19319angular.module('far.models.event.eventReport', ['far.helpers.users'])
19320    .service('eventReport', ["$log", "$http", "usersHelper", function ($log, $http, usersHelper) {
19321        this.new = function (eventReportData, userTypes) {
19322            eventReportData.eventReportEdit = 0;
19323
19324            return new EventReport(eventReportData, userTypes);
19325        };
19326
19327        this.get = function (eventId, userTypes, callback) {
19328            var eventReport = new EventReport({eventReportEdit: 1}, userTypes);
19329
19330            $http.get(Routing.generate('api_event_get_event_report', {id: eventId}))
19331                .then(function (response) {
19332                    eventReport.update(response.data);
19333
19334                    if (typeof callback == 'function') {
19335                        callback(eventReport);
19336                    }
19337                })
19338                .catch(function (response) {
19339                    $log.error(response);
19340                });
19341
19342            return eventReport;
19343        };
19344
19345        function EventReport(eventData, userTypes) {
19346            if (!eventData.users) {
19347                eventData.users = [];
19348            }
19349
19350            angular.merge(this, eventData);
19351
19352            Object.defineProperty(this, 'update', {
19353                enumerable: false,
19354                get: function () {
19355                    return function (eventData) {
19356                        if (eventData.documents_files) {
19357                            delete this.documents_files;
19358                        }
19359
19360                        angular.merge(this, eventData);
19361
19362                        this.updateUsers();
19363
19364                        this.ascents.forEach(function (ascent) {
19365                            ascent.users = [];
19366
19367                            if (angular.isArray(ascent.ascent_users)) {
19368                                ascent.ascent_users.forEach(function (user) {
19369                                    if (user.ascent_user_type_id.system_name === 'chief') {
19370                                        ascent.user_chief = user.user;
19371                                    } else if (user.ascent_user_type_id.system_name === 'instructor') {
19372                                        ascent.instructor = user.user;
19373                                    } else {
19374                                        ascent.users.push(user.user);
19375                                    }
19376                                })
19377                            }
19378                        });
19379
19380                        return this;
19381                    }
19382                }
19383            });
19384
19385            Object.defineProperty(this, 'save', {
19386                enumerable: false,
19387                get: function () {
19388                    return function () {
19389                        var method = this.eventReportEdit ? 'put' : 'post',
19390                            url = this.eventReportEdit ?
19391                                Routing.generate('api_event_put_event_report', {id: this.event.id}) :
19392                                Routing.generate('api_event_post_event_report');
19393
19394                        // Могу преобразовывать data как хочу.
19395                        var data = angular.extend({}, this);
19396
19397                        if (data.documents_files && data.documents_files.length > 0) {
19398                            data.documents_files = data.documents_files.filter(function (documentFile) {
19399                                return angular.isDefined(documentFile.serverData);
19400                            }).map(function (documentFile) {
19401                                return documentFile.serverData.id;
19402                            });
19403                        }
19404
19405
19406                        data.ascents = data.ascents.map(function (ascent) {
19407                            var users = [];
19408
19409                            if (ascent.user_chief) {
19410                                users.push({
19411                                    user: ascent.user_chief.id,
19412                                    ascent_user_type_id: data.ascent_user_types.chief.id
19413                                });
19414                            }
19415
19416                            if (ascent.instructor) {
19417                                users.push({
19418                                    user: ascent.instructor.id,
19419                                    ascent_user_type_id: data.ascent_user_types.instructor.id
19420                                });
19421                            }
19422
19423                            ascent.users.forEach(function (user) {
19424                                users.push({
19425                                    user: {
19426                                        id: user.id,
19427                                        email: user.email,
19428                                        fio: user.fio
19429                                    },
19430                                    ascent_user_type_id: data.ascent_user_types.participant.id
19431                                })
19432                            });
19433
19434                            ascent.ascent_users = users;
19435                            ascent.ascent_mountain_route = ascent.ascent_mountain_route ? ascent.ascent_mountain_route.id : 0;
19436                            ascent.ascent_type = ascent.ascent_type ? ascent.ascent_type.id : null;
19437
19438                            delete(ascent.users);
19439                            delete(ascent.user_chief);
19440
19441                            return ascent;
19442                        });
19443
19444                        delete(data.ascent_user_types);
19445                        delete(data.eventUserTypes);
19446
19447                        return $http[method](url, data);
19448                    }
19449                }
19450            });
19451
19452            usersHelper.initUsers(this, userTypes, 'users', 'event_application_user_type');
19453        }
19454    }]);
19455
19456},{"../../helpers/users/users.module":169}],210:[function(require,module,exports){
19457'use strict';
19458
19459angular.module('far.models.event.status', [])
19460    .service('eventStatus', function () {
19461        var list = [{
19462            id: false,
19463            status: 'Черновик'
19464        }, {
19465            id: true,
19466            status: 'Одобрено'
19467        }];
19468
19469        Object.defineProperty(this, 'list', {
19470            get: function () {
19471                return list;
19472            }
19473        });
19474    });
19475
19476},{}],211:[function(require,module,exports){
19477'use strict';
19478
19479angular.module('far.models.insuranceApplication', [])
19480.service('insuranceApplication', ["$log", "$http", function ($log, $http) {
19481    this.new = function (applicationData) {
19482        return new InsuranceApplication(applicationData);
19483    };
19484
19485    function InsuranceApplication(applicationData) {
19486        var persons = [];
19487
19488        angular.merge(this, applicationData);
19489
19490        if (angular.isUndefined(this.persons_list)) {
19491            Object.defineProperty(this, 'persons_list', {
19492                enumerable: true,
19493                set: function(data) {
19494                    data.forEach(function(person) {
19495                        persons.push(person);
19496                    });
19497                },
19498                get: function() {
19499                    return persons;
19500                }
19501            });
19502        }
19503
19504        Object.defineProperty(this, 'update', {
19505            enumerable: false,
19506            get: function() {
19507                return function(applicationData) {
19508                    angular.merge(this, applicationData);
19509                }
19510            }
19511        });
19512
19513        Object.defineProperty(this, 'save', {
19514            enumerable: false,
19515            get: function() {
19516                return function() {
19517                    var method = 'post',
19518                        url = Routing.generate('api_post_insurance_application');
19519
19520                    var data = angular.merge({}, this);
19521
19522                    // Для формы 3 типа в поле суммы сливаем 2 значения
19523                    if (angular.isDefined(data.insurance_sum1)) {
19524                        data.insurance_sum = data.insurance_sum1.name + ' (Е-экстрим) + ' + data.insurance_sum2.name + ' (от НС)';
19525                        delete data.insurance_sum1;
19526                        delete data.insurance_sum2;
19527                    }
19528                    // Для форм 1 и 2 типов - просто берем выбранное значение
19529                    else {
19530                        data.insurance_sum = data.insurance_sum.name;
19531                    }
19532
19533                    if (angular.isDefined(data.sport_kinds)) {
19534                        data.sport_kinds = data.sport_kinds.name;
19535                    }
19536                    data.submit_time = new Date();
19537                    data.persons = data.persons_list;
19538                    delete data.persons_list;
19539                    
19540                    return $http[method](url, data);
19541                }
19542            }
19543        });
19544
19545    } // function InsuranceApplication
19546
19547}]);
19548
19549},{}],212:[function(require,module,exports){
19550'use strict';
19551
19552angular.module('far.models.mountains.mountains', [])
19553.service('mountains', ["$log", "$http", function($log, $http) {
19554	var list = [],
19555		firstListQuery = true,
19556		listQueryProgress = false;
19557
19558	// TODO: Add 'countries' property
19559
19560	Object.defineProperty(this, 'list', {
19561		get: function() {
19562			if (firstListQuery && !listQueryProgress) {
19563				listQueryProgress = true;
19564
19565				$http.get(Routing.generate(''))
19566					.then(function(response) {
19567						response.data.forEach(function(mountainData) {
19568							list.push(new Mountain(mountainData));
19569						});
19570
19571						firstListQuery = false;
19572						listQueryProgress = false;
19573					})
19574					.catch(function(response) {
19575						listQueryProgress = false;
19576						$log.error(response);
19577					});
19578			}
19579
19580			return list;
19581		}
19582	});
19583
19584	this.new = function(mountainData) {
19585		return new Mountain(mountainData);
19586	};
19587
19588	this.delete = function(mountain, callback) {
19589		return $http.delete(Routing.generate('api_entities_delete_mountain', {mountain: mountain.id}))
19590				.then(function() {
19591					mountain = null;
19592
19593					if (typeof callback == 'function') {
19594						callback();
19595					}
19596				})
19597				.catch(function(response) {
19598					$log.error(response);
19599				});
19600	};
19601
19602	this.restore = function(region, callback) {
19603		return $http.patch(Routing.generate('api_entities_patch_mountain', {id: region.id}))
19604				.then(function() {
19605					if (typeof callback == 'function') {
19606						callback();
19607					}
19608				})
19609				.catch(function(response) {
19610					$log.error(response);
19611				});
19612	};
19613
19614	this.get = function(mountainId, callback) {
19615		var mountain = new Mountain({});
19616
19617		$http.get(Routing.generate('api_entities_get_mountain', {mountain: mountainId}))
19618				.then(function(response) {
19619					mountain.update(response.data);
19620
19621					if (typeof callback == 'function') {
19622						callback(mountain);
19623					}
19624				})
19625				.catch(function(response) {
19626					$log.error(response);
19627				});
19628
19629		return mountain;
19630	};
19631
19632	function Mountain(mountainData) {
19633		var peaks = [],
19634			firstPeaksQuery = true,
19635			peaksQueryProgress = false;
19636
19637		angular.merge(this, mountainData);
19638
19639		if (angular.isUndefined(this.mountain_peaks)) {
19640			Object.defineProperty(this, 'mountain_peaks', {
19641				enumerable: true,
19642				set: function(data) {
19643					data.forEach(function(area) {
19644						peaks.push(area);
19645					});
19646				},
19647				get: function() {
19648					if (firstPeaksQuery && !peaksQueryProgress && angular.isDefined(this.id)) {
19649						peaksQueryProgress = true;
19650
19651						$http.get(Routing.generate('api_entities_get_mountain_peaks', {mountain: this.id}))
19652							.then(function(response) {
19653								// Мы еще не получили информации о районах
19654								if (peaks.length == 0) {
19655									response.data.forEach(function(peak) {
19656										peaks.push(peak);
19657									});
19658								}
19659
19660								firstPeaksQuery = false;
19661								peaksQueryProgress = false;
19662							})
19663							.catch(function(response) {
19664								peaksQueryProgress = false;
19665								$log.error(response);
19666							});
19667					}
19668
19669					return peaks;
19670				}
19671			});
19672		}
19673
19674		Object.defineProperty(this, 'update', {
19675			enumerable: false,
19676			get: function() {
19677				return function(mountainData) {
19678					angular.merge(this, mountainData);
19679				}
19680			}
19681		});
19682
19683		Object.defineProperty(this, 'save', {
19684			enumerable: false,
19685			get: function() {
19686				return function() {
19687					var method = this.id ? 'put' : 'post',
19688							url = this.id ?
19689									Routing.generate('api_entities_put_mountain', {mountain: this.id}) :
19690									Routing.generate('api_entities_post_mountain');
19691
19692					var data = angular.merge({}, this);
19693					data.mountain_peaks = data.mountain_peaks.map(function(peak) {
19694							peak.mountainArea = peak.mountain_area.id;
19695							peak.mountain_area = undefined;
19696						return peak;
19697					});
19698
19699					return $http[method](url, data);
19700				}
19701			}
19702		});
19703	}
19704}]);
19705
19706},{}],213:[function(require,module,exports){
19707'use strict';
19708
19709angular.module('far.models.mountains.peaks', [])
19710    .service('mountainPeaks', ["$log", "$http", "$q", function ($log, $http, $q) {
19711        this.getByArea = function (area_id) {
19712            return $http.get(Routing.generate('api_entities_get_mountainpeak', {mountainArea: area_id}))
19713                .then(function (response) {
19714                    return response.data;
19715                }, function (response) {
19716                    $q.reject(response);
19717                    $log.error(response);
19718                });
19719        };
19720
19721        this.new = function (mountainPeakData) {
19722            return new MountainPeak(mountainPeakData);
19723        };
19724
19725        this.get = function (id, callback) {
19726            var mountainPeak = new MountainPeak({});
19727
19728            $http.get(Routing.generate('api_get_mountain_peak', {mountainPeak: id}))
19729                .then(function (response) {
19730                    mountainPeak.update(response.data);
19731
19732                    if (typeof callback == 'function') {
19733                        callback(mountainPeak);
19734                    }
19735                }, function (response) {
19736                    $q.reject(response);
19737                    $log.error(response);
19738                });
19739
19740            return mountainPeak;
19741        };
19742
19743        this.delete = function (mountainPeak, callback) {
19744            return $http.delete(Routing.generate('api_delete_mountain_peak', {mountainPeak: mountainPeak.id}))
19745                .then(function () {
19746                    mountainPeak = null;
19747
19748                    if (typeof callback == 'function') {
19749                        callback();
19750                    }
19751                })
19752                .catch(function (response) {
19753                    $log.error(response);
19754                });
19755        };
19756
19757        this.restore = function (region, callback) {
19758            return $http.patch(Routing.generate('api_patch_mountain_peak', {id: region.id}))
19759                .then(function () {
19760                    if (typeof callback == 'function') {
19761                        callback();
19762                    }
19763                })
19764                .catch(function (response) {
19765                    $log.error(response);
19766                });
19767        };
19768
19769        function MountainPeak(mountainPeakData) {
19770            angular.merge(this, mountainPeakData);
19771
19772            Object.defineProperty(this, 'update', {
19773                enumerable: false,
19774                get: function () {
19775                    return function (mountainPeakData) {
19776                        angular.merge(this, mountainPeakData);
19777                    }
19778                }
19779            });
19780
19781            Object.defineProperty(this, 'save', {
19782                enumerable: false,
19783                get: function () {
19784                    return function () {
19785                        var method = this.id ? 'put' : 'post',
19786                            url = this.id ?
19787                                Routing.generate('api_put_mountain_peak', {mountain_peak: this.id}) :
19788                                Routing.generate('api_post_mountain_peak');
19789
19790                        var data = angular.merge({}, this);
19791
19792                        data.mountainArea = data.mountain_area;
19793
19794                        delete data.mountain_area;
19795
19796                        return $http[method](url, data);
19797                    }
19798                }
19799            });
19800        }
19801    }]);
19802
19803},{}],214:[function(require,module,exports){
19804'use strict';
19805
19806angular.module('far.models.mountains.regions', [])
19807.service('mountainRegions', ["$log", "$http", function($log, $http) {
19808	var list = [],
19809		firstListQuery = true,
19810		listQueryProgress = false,
19811		addBlank = false;
19812
19813	Object.defineProperty(this, 'list', {
19814		get: function() {
19815			if (firstListQuery && !listQueryProgress) {
19816				listQueryProgress = true;
19817
19818				$http.get(Routing.generate('api_entities_get_mountainregions'))
19819					.then(function(response) {
19820
19821                        response.data.sort(function(a, b) {
19822                            return parseInt(a.name) - parseInt(b.name);
19823                        });
19824
19825						response.data.forEach(function(regionData) {
19826							list.push(new MountainRegion(regionData));
19827						});
19828
19829						firstListQuery = false;
19830						listQueryProgress = false;
19831					})
19832					.catch(function(response) {
19833						listQueryProgress = false;
19834						$log.error(response);
19835					});
19836			}
19837
19838			return list;
19839		}
19840	});
19841
19842    this.setAddBlank = function(value) {
19843        addBlank = value;
19844    };
19845
19846	this.new = function(regionData) {
19847		return new MountainRegion(regionData);
19848	};
19849
19850	this.delete = function(region, callback) {
19851		return $http.delete(Routing.generate('api_entities_delete_mountainregion', {mountainRegion: region.id}))
19852				.then(function() {
19853					region = null;
19854
19855					if (typeof callback == 'function') {
19856						callback();
19857					}
19858				})
19859				.catch(function(response) {
19860					$log.error(response);
19861				});
19862	};
19863
19864	this.restore = function(region, callback) {
19865		return $http.patch(Routing.generate('api_entities_patch_mountainregion', {id: region.id}))
19866            .then(function() {
19867                    if (typeof callback == 'function') {
19868                        callback();
19869                    }
19870				})
19871				.catch(function(response) {
19872					$log.error(response);
19873				});
19874	};
19875
19876	this.get = function(regionId, callback) {
19877		var region = new MountainRegion({});
19878
19879		$http.get(Routing.generate('api_entities_get_mountainregion', {mountainRegion: regionId}))
19880			.then(function(response) {
19881				region = region.update(response.data);
19882
19883				if (typeof callback == 'function') {
19884					callback();
19885				}
19886			})
19887			.catch(function(response) {
19888				$log.error(response);
19889			});
19890
19891		return region;
19892	};
19893
19894	function MountainRegion(regionData) {
19895		var areas = [],
19896			firstAreasQuery = true,
19897			areasQueryProgress = false;
19898
19899		angular.merge(this, regionData);
19900
19901		if (angular.isUndefined(this.mountain_areas)) {
19902			Object.defineProperty(this, 'mountain_areas', {
19903				enumerable: true,
19904				set: function(data) {
19905					if (angular.isArray(data)) {
19906						data.forEach(function(area) {
19907							areas.push(area);
19908						});
19909					}
19910				},
19911				get: function() {
19912					if (firstAreasQuery && !areasQueryProgress && angular.isDefined(this.id)) {
19913						areasQueryProgress = true;
19914
19915						$http.get(Routing.generate('api_entities_get_mountainarea', {mountainRegion: this.id}))
19916							.then(function(response) {
19917								// Мы еще не получили информации о районах
19918								if ( areas.length == 0 && response.data.length ) {
19919                                    if (addBlank == true) {
19920                                        // Пункт для очистки выпадающего списка
19921                                        areas.push({
19922                                            id: 0,
19923                                            name: '...'
19924                                        });
19925                                    }
19926									response.data.forEach(function(area) {
19927										areas.push(area);
19928									});
19929								}
19930
19931								firstAreasQuery = false;
19932								areasQueryProgress = false;
19933							})
19934							.catch(function(response) {
19935								areasQueryProgress = false;
19936								$log.error(response);
19937							});
19938					}
19939
19940					return areas;
19941				}
19942			});
19943		}
19944
19945		Object.defineProperty(this, 'update', {
19946			enumerable: false,
19947			get: function() {
19948				return function(regionData) {
19949					angular.merge(this, regionData);
19950				}
19951			}
19952		});
19953
19954		Object.defineProperty(this, 'save', {
19955			enumerable: false,
19956			get: function() {
19957				return function() {
19958					// TODO: Rest API url
19959					var method = this.id ? 'put' : 'post',
19960						url = this.id ?
19961							Routing.generate('api_entities_put_mountainregion', {mountainRegion: this.id}) :
19962							Routing.generate('api_entities_post_mountainregion');
19963
19964					return $http[method](url, this);
19965				}
19966			}
19967		});
19968	}
19969}]);
19970
19971},{}],215:[function(require,module,exports){
19972'use strict';
19973
19974angular.module('far.models.mountains.routeComplexities', [])
19975	.service('mountainRouteComplexities', ["$log", "$http", function($log, $http) {
19976		var list = [],
19977			firstListQuery = true,
19978			listQueryProgress = false;
19979
19980		Object.defineProperty(this, 'list', {
19981			get: function() {
19982				if (firstListQuery && !listQueryProgress) {
19983					listQueryProgress = true;
19984
19985					$http.get(Routing.generate('api_entities_get_mountainroutecomplexities'))
19986						.then(function(response) {
19987							response.data.forEach(function(routeData) {
19988								list.push(routeData);
19989							});
19990
19991							firstListQuery = false;
19992							listQueryProgress = false;
19993						})
19994						.catch(function(response) {
19995							listQueryProgress = false;
19996							$log.error(response);
19997						});
19998				}
19999
20000				return list;
20001			}
20002		});
20003	}]);
20004
20005},{}],216:[function(require,module,exports){
20006'use strict';
20007
20008angular.module('far.models.mountains.routeTypes', [])
20009	.service('mountainRouteTypes', ["$log", "$http", function($log, $http) {
20010		var list = [],
20011			firstListQuery = true,
20012			listQueryProgress = false;
20013
20014		Object.defineProperty(this, 'list', {
20015			get: function() {
20016				if (firstListQuery && !listQueryProgress) {
20017					listQueryProgress = true;
20018
20019					$http.get(Routing.generate('api_entities_get_mountainroutetypes'))
20020						.then(function(response) {
20021							response.data.forEach(function(routeData) {
20022								list.push(routeData);
20023							});
20024
20025							firstListQuery = false;
20026							listQueryProgress = false;
20027						})
20028						.catch(function(response) {
20029							listQueryProgress = false;
20030							$log.error(response);
20031						});
20032				}
20033
20034				return list;
20035			}
20036		});
20037	}]);
20038
20039},{}],217:[function(require,module,exports){
20040'use strict';
20041
20042angular.module('far.models.mountains.routes', [])
20043	.service('mountainRoutes', ["$log", "$http", function($log, $http) {
20044		var list = [],
20045			firstListQuery = true,
20046			listQueryProgress = false;
20047
20048		Object.defineProperty(this, 'list', {
20049			get: function() {
20050				if (firstListQuery && !listQueryProgress) {
20051					listQueryProgress = true;
20052
20053					$http.get(Routing.generate(''))
20054						.then(function(response) {
20055							response.data.forEach(function(routeData) {
20056								list.push(new Mountain(routeData));
20057							});
20058
20059							firstListQuery = false;
20060							listQueryProgress = false;
20061						})
20062						.catch(function(response) {
20063							listQueryProgress = false;
20064							$log.error(response);
20065						});
20066				}
20067
20068				return list;
20069			}
20070		});
20071
20072		this.new = function(routeData) {
20073			return new MountainRoute(routeData);
20074		};
20075
20076		this.delete = function(route, callback) {
20077			return $http.delete(Routing.generate('api_entities_delete_mountain_route', {mountainRoute: route.id}))
20078					.then(function() {
20079						route = null;
20080
20081						if (typeof callback == 'function') {
20082							callback();
20083						}
20084					})
20085					.catch(function(response) {
20086						$log.error(response);
20087					});
20088		};
20089
20090		this.restore = function(region, callback) {
20091			return $http.patch(Routing.generate('api_entities_patch_mountain_route', {id: region.id}))
20092					.then(function() {
20093						if (typeof callback == 'function') {
20094							callback();
20095						}
20096					})
20097					.catch(function(response) {
20098						$log.error(response);
20099					});
20100		};
20101
20102		this.get = function(routeId, callback) {
20103			var route = new MountainRoute({});
20104
20105			$http.get(Routing.generate('api_entities_get_mountainroute', {mountainRoute: routeId}))
20106				.then(function(response) {
20107					route.update(response.data);
20108
20109					if (typeof callback == 'function') {
20110						callback(route);
20111					}
20112				})
20113				.catch(function(response) {
20114					$log.error(response);
20115				});
20116
20117			return route;
20118		};
20119
20120		this.getPopular = function(filters) {
20121			filters = angular.merge({
20122				offset: 0,
20123				limit: 8,
20124				order_by: 'ascents_count,desc',
20125				with_images: true
20126			}, filters);
20127
20128			return $http.get(Routing.generate('api_entities_get_mountainroutes', filters))
20129				.then(function(response) {
20130					return response.data;
20131				}).catch(function(response) {
20132					$log.error(response);
20133					return $q.reject(response);
20134				});
20135		};
20136
20137		function MountainRoute(routeData) {
20138			angular.merge(this, routeData);
20139
20140			Object.defineProperty(this, 'update', {
20141				enumerable: false,
20142				get: function() {
20143					return function(mountainData) {
20144						angular.merge(this, mountainData);
20145
20146						return this;
20147					}
20148				}
20149			});
20150
20151			Object.defineProperty(this, 'save', {
20152				enumerable: false,
20153				get: function() {
20154					return function() {
20155						var method = this.id ? 'put' : 'post',
20156							url = this.id ?
20157								Routing.generate('api_entities_put_mountain_route', {mountainRoute: this.id}) :
20158								Routing.generate('api_entities_post_mountain_route');
20159
20160						// TODO: Грязный хак
20161						var data = angular.merge({}, this);
20162
20163						var peaks = [];
20164
20165						angular.forEach(data.mountain_peaks, function(peak) {
20166							if ( peaks.indexOf( peak.id ) == -1 ) {
20167								peaks.push( peak.id );
20168							}
20169						});
20170
20171						data.mountain_peaks = peaks;
20172						data.mountain_route_type = data.mountain_route_type.id;
20173						data.mountain_route_complexity = data.mountain_route_complexity.id;
20174						data.user = data.user.id;
20175
20176						angular.forEach(data.documents_files, function(document_file, i) {
20177							data.documents_files[i]=document_file;
20178						});
20179
20180                        if (angular.isObject(data.camp)) {
20181                            data.camp = data.camp.id;
20182                        }
20183
20184						return $http[method](url, data);
20185					}
20186				}
20187			});
20188		}
20189	}]);
20190
20191},{}],218:[function(require,module,exports){
20192'use strict';
20193
20194angular.module('far.models.news', [])
20195    .service('News', ["$log", "$http", function ($log, $http) {
20196        this.new = function (data) {
20197            return new News(data);
20198        };
20199
20200        this.delete = function (route, callback) {
20201            return $http.delete(Routing.generate('api_delete_news', {news: route.id}))
20202                .then(function () {
20203                    route = null;
20204
20205                    if (typeof callback == 'function') {
20206                        callback();
20207                    }
20208                }, function errorCallback(response) {
20209                    $log.error(response);
20210                });
20211        };
20212
20213        this.restore = function (route) {
20214            return $http.patch(Routing.generate('api_patch_news', {id: route.id}))
20215                .then(function () {
20216                    return route = null;
20217                }, function errorCallback(response) {
20218                    $log.error(response);
20219                });
20220        };
20221
20222        this.getView = function (routeId, callback) {
20223            var route = new News({});
20224
20225            $http.get(Routing.generate('api_get_newsview', {news: routeId}))
20226                .then(function (response) {
20227                    route.update(response.data);
20228
20229                    if (typeof callback == 'function') {
20230                        callback(route);
20231                    }
20232                }, function errorCallback(response) {
20233                    $log.error(response);
20234                });
20235
20236            return route;
20237        };
20238
20239        this.get = function (routeId, callback) {
20240            var route = new News({});
20241
20242            $http.get(Routing.generate('api_get_news', {news: routeId}))
20243                .then(function (response) {
20244                    route.update(response.data);
20245
20246                    if (typeof callback == 'function') {
20247                        callback(route);
20248                    }
20249                }, function errorCallback(response) {
20250                    $log.error(response);
20251                });
20252
20253            return route;
20254        };
20255
20256        function News(data) {
20257            angular.merge(this, data);
20258
20259            Object.defineProperty(this, 'update', {
20260                enumerable: false,
20261                get: function () {
20262                    return function (data) {
20263                        angular.merge(this, data);
20264
20265                        return this;
20266                    }
20267                }
20268            });
20269
20270            Object.defineProperty(this, 'save', {
20271                enumerable: false,
20272                get: function () {
20273                    return function () {
20274                        var method = this.id ? 'put' : 'post',
20275                            url = this.id ?
20276                                Routing.generate('api_put_news', {news: this.id}) :
20277                                Routing.generate('api_post_news');
20278
20279                        // TODO: Грязный хак
20280                        var data = angular.merge({}, this);
20281
20282                        if ( angular.isArray( data.disciplines ) ) {
20283                            data.disciplines = data.disciplines.map(function(discipline) {
20284                                return discipline.id;
20285                            });
20286                        }
20287
20288                        if ( angular.isArray( data.categories ) ) {
20289                            data.categories = data.categories.map(function(category) {
20290                                return category.id;
20291                            });
20292                        }
20293
20294                        if ( angular.isArray( data.committees ) ) {
20295                            data.committees = data.committees.map(function(committee) {
20296                                return committee.id;
20297                            });
20298
20299                        if ( angular.isObject( data.avatar ) ) {
20300                            data.avatar = data.avatar.id;
20301                        }
20302
20303                        return $http[method](url, data);
20304                    }
20305                }
20306            }});
20307        }
20308    }]);
20309
20310},{}],219:[function(require,module,exports){
20311/**
20312 * Created by Phatbass on 21/02/16.
20313 */
20314
20315'use strict';
20316
20317// TODO: Add all urls
20318angular.module('far.models.newsCategory', [])
20319    .service('NewsCategory', ["$log", "$http", function ($log, $http) {
20320        var list = [],
20321            firstListQuery = true,
20322            listQueryProgress = false;
20323
20324        Object.defineProperty(this, 'list', {
20325            get: function () {
20326                if (firstListQuery && !listQueryProgress) {
20327                    listQueryProgress = true;
20328                    $http.get(Routing.generate('api_get_news_categories'))
20329                        .then(function (response) {
20330                            response.data.forEach(function (item) {
20331                                item.selected = false;
20332                                list.push(item);
20333                            });
20334
20335                            firstListQuery = false;
20336                            listQueryProgress = false;
20337                        })
20338                        .catch(function (response) {
20339                            $log.error(response);
20340                            listQueryProgress = false;
20341                        });
20342                }
20343
20344                return list;
20345            }
20346        });
20347    }]);
20348
20349},{}],220:[function(require,module,exports){
20350'use strict';
20351
20352angular.module('far.models.notice', [])
20353    .service('Notice', ["$log", "$http", function ($log, $http) {
20354        this.getByUser = function (user, offset, limit, callback, type) {
20355            return $http.get(Routing.generate('api_get_notices', {user: user, offset: offset, limit: limit, type: type ? type : 0}))
20356                .then(function (response) {
20357                    if (typeof callback == 'function') {
20358                        return callback(response);
20359                    }
20360                }, function errorCallback(response) {
20361                    $log.error(response);
20362                });
20363        };
20364
20365        this.delete = function (route, callback) {
20366            return $http.delete(Routing.generate('api_delete_notice', {notice: route.id}))
20367                .then(function () {
20368                    route = null;
20369
20370                    if (typeof callback == 'function') {
20371                        callback();
20372                    }
20373                }, function errorCallback(response) {
20374                    $log.error(response);
20375                });
20376        };
20377
20378        this.restore = function (route) {
20379            return $http.patch(Routing.generate('api_patch_notice', {id: route.id}))
20380                .then(function () {
20381                    return route = null;
20382                }, function errorCallback(response) {
20383                    $log.error(response);
20384                });
20385        };
20386
20387        this.new = function (data) {
20388            return new Notice(data);
20389        };
20390
20391        function Notice(data) {
20392            angular.merge(this, data);
20393
20394            Object.defineProperty(this, 'update', {
20395                enumerable: false,
20396                get: function () {
20397                    return function (data) {
20398                        angular.merge(this, data);
20399
20400                        return this;
20401                    }
20402                }
20403            });
20404        }
20405    }]);
20406
20407},{}],221:[function(require,module,exports){
20408'use strict';
20409
20410angular.module('far.models.page', [])
20411    .service('Page', ["$log", "$http", function ($log, $http) {
20412        var list = [];
20413
20414        Object.defineProperty(this, 'list', {
20415            get: function () {
20416                list.push({
20417                    id: 0,
20418                    name: 'Homepage'
20419                });
20420
20421                $http.get(Routing.generate('api_get_pages'))
20422                    .then(function (response) {
20423                        response.data.forEach(function (routeData) {
20424                            list.push(routeData);
20425                        });
20426                    }, function errorCallback(response) {
20427                        $log.error(response);
20428                    });
20429
20430                return list;
20431            }
20432        });
20433
20434        this.new = function (data) {
20435            return new Page(data);
20436        };
20437
20438        this.delete = function (route, callback) {
20439            return $http.delete(Routing.generate('api_delete_page', {page: route.id}))
20440                .then(function () {
20441                    route = null;
20442
20443                    if (typeof callback == 'function') {
20444                        callback();
20445                    }
20446                }, function errorCallback(response) {
20447                    $log.error(response);
20448                });
20449        };
20450
20451        this.restore = function (route) {
20452            return $http.patch(Routing.generate('api_patch_page', {id: route.id}))
20453                .then(function () {
20454                    return route = null;
20455                }, function errorCallback(response) {
20456                    $log.error(response);
20457                });
20458        };
20459
20460        this.get = function (routeId, callback) {
20461            var route = new Page({});
20462
20463            $http.get(Routing.generate('api_get_page', {page: routeId}))
20464                .then(function (response) {
20465                    route.update(response.data);
20466
20467                    if (typeof callback == 'function') {
20468                        callback(route);
20469                    }
20470                }, function errorCallback(response) {
20471                    $log.error(response);
20472                });
20473
20474            return route;
20475        };
20476
20477        function Page(data) {
20478            angular.merge(this, data);
20479
20480            Object.defineProperty(this, 'update', {
20481                enumerable: false,
20482                get: function () {
20483                    return function (data) {
20484                        angular.merge(this, data);
20485
20486                        return this;
20487                    }
20488                }
20489            });
20490
20491            Object.defineProperty(this, 'save', {
20492                enumerable: false,
20493                get: function () {
20494                    return function () {
20495                        var method = this.id ? 'put' : 'post',
20496                            url = this.id ?
20497                                Routing.generate('api_put_page', {page: this.id}) :
20498                                Routing.generate('api_post_page');
20499
20500                        // TODO: Грязный хак
20501                        var data = angular.merge({}, this);
20502
20503                        if ( angular.isObject( data.parent ) ) {
20504                            data.parent = data.parent.id;
20505                        }
20506
20507                        if ( data.parent == 0 ) {
20508                            data.parent = null;
20509                        }
20510
20511                        return $http[method](url, data);
20512                    }
20513                }
20514            });
20515        }
20516    }]);
20517
20518},{}],222:[function(require,module,exports){
20519'use strict';
20520
20521angular.module('far.models.partners', [])
20522	.service('partners', ["$log", "$http", function($log, $http) {
20523		var list = [],
20524			firstListQuery = true,
20525			listQueryProgress = false;
20526
20527		Object.defineProperty(this, 'list', {
20528			get: function() {
20529				if (firstListQuery && !listQueryProgress) {
20530					listQueryProgress = true;
20531					$http.get(Routing.generate('api_partner_get_partners'))
20532						.then(function(response) {
20533							response.data.forEach(function(item) {
20534								item.selected = false;
20535								list.push(item);
20536							});
20537
20538							firstListQuery = false;
20539							listQueryProgress = false;
20540						})
20541						.catch(function(response) {
20542							$log.error(response);
20543							listQueryProgress = false;
20544						});
20545				}
20546
20547				return list;
20548			}
20549		});
20550	}]);
20551
20552},{}],223:[function(require,module,exports){
20553'use strict';
20554
20555angular.module('far.models.project.project', [])
20556    .service('Project', ["$log", "$http", "usersHelper", function ($log, $http, usersHelper) {
20557        this.new = function (data, userTypes) {
20558            return new Project(data, userTypes);
20559        };
20560
20561        this.delete = function (route, callback) {
20562            return $http.delete(Routing.generate('api_delete_project', {project: route.id}))
20563                .then(function () {
20564                    route = null;
20565
20566                    if (typeof callback == 'function') {
20567                        callback();
20568                    }
20569                }, function errorCallback(response) {
20570                    $log.error(response);
20571                });
20572        };
20573
20574        this.restore = function (route) {
20575            return $http.patch(Routing.generate('api_patch_project', {id: route.id}))
20576                .then(function () {
20577                    return route = null;
20578                }, function errorCallback(response) {
20579                    $log.error(response);
20580                });
20581        };
20582
20583        this.get = function (routeId, userTypes, callback) {
20584            var route = new Project({}, userTypes);
20585
20586            $http.get(Routing.generate('api_event_get_event', {id: routeId}))
20587                .then(function (response) {
20588                    if (!response.data.background_image) {
20589                        delete response.data.background_image;
20590                    }
20591
20592                    route.update(response.data);
20593
20594                    route.type = route.type.id;
20595
20596                    route.event_project.accepted = {id: route.event_project.accepted};
20597
20598                    route.event_project.participants = {
20599                        min: route.event_project.participants_count_from,
20600                        max: route.event_project.participants_count_to
20601                    };
20602
20603                    if (typeof callback == 'function') {
20604                        callback(route);
20605                    }
20606                }, function errorCallback(response) {
20607                    $log.error(response);
20608                });
20609
20610            return route;
20611        };
20612
20613        function Project(data, userTypes) {
20614            if (!data.event_project) {
20615                data.event_project = {
20616                    documents: {},
20617                    users: [],
20618                    participants: {
20619                        min: 1,
20620                        max: 500
20621                    }
20622                }
20623            }
20624
20625            angular.merge(this, data);
20626
20627            Object.defineProperty(this, 'update', {
20628                enumerable: false,
20629                get: function () {
20630                    return function (data) {
20631                        if (data.event_project.documents_files) {
20632                            delete this.event_project.documents_files;
20633                        }
20634
20635                        angular.merge(this, data);
20636
20637                        this.event_project.updateUsers();
20638
20639                        return this;
20640                    }
20641                }
20642            });
20643
20644            Object.defineProperty(this, 'save', {
20645                enumerable: false,
20646                get: function () {
20647                    return function () {
20648                        var method = this.id ? 'put' : 'post',
20649                            url = this.id ?
20650                                Routing.generate('api_event_put_event', {event: this.id}) :
20651                                Routing.generate('api_event_post_event');
20652
20653                        // Могу преобразовывать data как хочу.
20654                        var data = angular.extend({}, this);
20655
20656                        data.disciplines = [data.disciplines.id];
20657
20658                        if (angular.isObject(data.event_project.accepted)) {
20659                            data.event_project.accepted = data.event_project.accepted.id;
20660                        }
20661
20662                        if (angular.isObject(data.camp)) {
20663                            data.camp = data.camp.id;
20664                        }
20665
20666                        data.event_project.participants_count_from = data.event_project.participants.min;
20667                        data.event_project.participants_count_to = data.event_project.participants.max;
20668
20669                        delete data.event_project.participants;
20670
20671                        data.partners = data.partners.filter(function (partner) {
20672                            return partner.selected;
20673                        }).map(function (partner) {
20674                            return partner.id;
20675                        });
20676
20677                        if (data.background_image && data.background_image.length > 0) {
20678                            data.background_image = data.background_image.filter(function (image) {
20679                                return angular.isDefined(image.serverData)
20680                            }).map(function (image) {
20681                                return image.serverData;
20682                            });
20683
20684                            data.background_image = data.background_image.length > 0 ? data.background_image[0] : undefined;
20685
20686                            data.background_image = data.background_image.id;
20687                        }
20688
20689                        if (data.event_project.documents_files && data.event_project.documents_files.length > 0) {
20690                            data.event_project.documents_files = data.event_project.documents_files.filter(function (documentFile) {
20691                                return angular.isDefined(documentFile.serverData);
20692                            }).map(function (documentFile) {
20693                                return documentFile.serverData.id;
20694                            });
20695                        }
20696
20697                        data.event_project.documents = Object.keys(data.event_project.documents).map(function (key) { return data.event_project.documents[key].id; });
20698
20699                        return $http[method](url, data);
20700                    };
20701                }
20702            });
20703
20704            usersHelper.initUsers(this.event_project, userTypes, 'users', 'event_project_user_type');
20705
20706            this.event_project.createUser(this.event_project.userTypes.user_organizer);
20707            this.event_project.createUser(this.event_project.userTypes.user_administrator);
20708        }
20709    }]);
20710
20711},{}],224:[function(require,module,exports){
20712'use strict';
20713
20714angular.module('far.models.project.projectReport', [])
20715    .service('ProjectReport', ["$log", "$http", "usersHelper", function ($log, $http, usersHelper) {
20716        this.new = function (data, userTypes) {
20717            return new Project(data, userTypes);
20718        };
20719
20720        this.delete = function (route, callback) {
20721            return $http.delete(Routing.generate('api_delete_project', {project: route.id}))
20722                .then(function () {
20723                    route = null;
20724
20725                    if (typeof callback == 'function') {
20726                        callback();
20727                    }
20728                }, function errorCallback(response) {
20729                    $log.error(response);
20730                });
20731        };
20732
20733        this.restore = function (route) {
20734            return $http.patch(Routing.generate('api_patch_project', {id: route.id}))
20735                .then(function () {
20736                    return route = null;
20737                }, function errorCallback(response) {
20738                    $log.error(response);
20739                });
20740        };
20741
20742        this.get = function (routeId, userTypes, callback) {
20743            var route = new Project({eventReportEdit: 1, eventId: routeId}, userTypes);
20744
20745            $http.get(Routing.generate('api_event_get_event_report', {id: routeId}))
20746                .then(function (response) {
20747                    route.update(response.data);
20748
20749                    if (typeof callback == 'function') {
20750                        callback(route);
20751                    }
20752                }, function errorCallback(response) {
20753                    $log.error(response);
20754                });
20755
20756            return route;
20757        };
20758
20759        function Project(data, userTypes) {
20760            this.users = [];
20761
20762            angular.merge(this, data);
20763
20764            Object.defineProperty(this, 'update', {
20765                enumerable: false,
20766                get: function () {
20767                    return function (data) {
20768                        if (data.documents_files) {
20769                            delete this.documents_files;
20770                        }
20771
20772                        angular.merge(this, data);
20773
20774                        this.updateUsers();
20775
20776                        return this;
20777                    }
20778                }
20779            });
20780
20781            Object.defineProperty(this, 'save', {
20782                enumerable: false,
20783                get: function () {
20784                    return function () {
20785                        var method = this.eventReportEdit ? 'put' : 'post',
20786                            url = this.eventReportEdit ?
20787                                Routing.generate('api_event_put_event_report', {id: this.eventId}) :
20788                                Routing.generate('api_event_post_event_report');
20789
20790                        // Могу преобразовывать data как хочу.
20791                        var data = angular.extend({}, this);
20792
20793                        if (data.documents_files && data.documents_files.length > 0) {
20794                            data.documents_files = data.documents_files.filter(function (documentFile) {
20795                                return angular.isDefined(documentFile.serverData);
20796                            }).map(function (documentFile) {
20797                                return documentFile.serverData.id;
20798                            });
20799                        }
20800
20801                        return $http[method](url, data);
20802                    }
20803                }
20804            });
20805
20806            usersHelper.initUsers(this, userTypes, 'users', 'event_project_user_t
20806ype');
20807        }
20808    }]);
20809
20810},{}],225:[function(require,module,exports){
20811'use strict';
20812
20813angular.module('far.models.project.projectUserType', [])
20814    .service('ProjectUserType', ["$log", "$http", "$q", function ($log, $http, $q) {
20815        var list = {},
20816            firstListQuery = true,
20817            listQueryProgress = false;
20818
20819        Object.defineProperty(this, 'list', {
20820            get: function () {
20821                if (firstListQuery && !listQueryProgress) {
20822                    listQueryProgress = true;
20823                    $http.get(Routing.generate('api_get_project_user_type'))
20824                        .then(function (response) {
20825                            list = angular.merge(list, response.data);
20826
20827                            listQueryProgress = false;
20828                            firstListQuery = false;
20829                        }, function errorCallback(response) {
20830                            listQueryProgress = false;
20831                            $log.error(response);
20832                        });
20833                }
20834
20835                return $q(function (resolve) {
20836                    resolve(list);
20837                });
20838            }
20839        });
20840    }]);
20841
20842},{}],226:[function(require,module,exports){
20843/**
20844 * Created by PhpStorm on 08.05.2017.
20845 * Author: Shabalin Pavel
20846 * Email: [email protected]
20847 */
20848'use strict';
20849
20850angular.module('far.models.subclub', [])
20851    .service('Subclub', ["$log", "$http", function ($log, $http) {
20852
20853        this.new = function (data) {
20854            return new Subclub(data);
20855        };
20856
20857        this.get = function (routeId, callback) {
20858            var route = new Subclub({});
20859
20860            $http.get(Routing.generate('api_get_subclub', {club: routeId}))
20861                .then(function (response) {
20862                    route.update(response.data);
20863
20864                    if (typeof callback == 'function') {
20865                        callback(route);
20866                    }
20867                }, function errorCallback(response) {
20868                    $log.error(response);
20869                });
20870
20871            return route;
20872        };
20873
20874        // Модель логики, содержит бизнес логику
20875        function Subclub(data) {
20876            angular.merge(this, data);
20877
20878            Object.defineProperty(this, 'update', {
20879                enumerable: false,
20880                get: function () {
20881                    return function (data) {
20882                        angular.merge(this, data);
20883
20884                        return this;
20885                    }
20886                }
20887            });
20888
20889            Object.defineProperty(this, 'save', {
20890                enumerable: false,
20891                get: function () {
20892                    return function () {
20893                        var method = this.id ? 'put' : 'post',
20894                            url = this.id ?
20895                                Routing.generate('api_put_subclub', {subclub: this.id}) :
20896                                Routing.generate('api_post_subclub');
20897
20898                        var data = angular.merge({}, this);
20899
20900                        if ( angular.isObject( data.country ) ) {
20901                            data.country = data.country.name;
20902                        }
20903
20904                        if ( angular.isObject( data.region ) ) {
20905                            data.region = data.region.name;
20906                        }
20907
20908                        if ( angular.isObject( data.city ) ) {
20909                            data.city = data.city.name;
20910                        }
20911
20912                        if ( angular.isObject( data.user ) ) {
20913                            data.user = data.user.id;
20914                        }
20915
20916                        if ( angular.isObject( data.avatar ) ) {
20917                            data.avatar = data.avatar.id;
20918                        }
20919
20920                        if ( angular.isObject( data.club ) ) {
20921                            data.parent = data.club.id;
20922                        }
20923
20924                        return $http[method](url, data);
20925                    }
20926                }
20927            });
20928        }
20929    }]);
20930
20931},{}],227:[function(require,module,exports){
20932'use strict';
20933
20934angular.module('far.models.token_users', [])
20935	.service('tokenUsers', ["$log", "$http", function($log, $http) {
20936		var list = [],
20937			firstListQuery = true,
20938			listQueryProgress = false;
20939
20940		Object.defineProperty(this, 'list', {
20941			get: function() {
20942				if (firstListQuery && !listQueryProgress) {
20943					listQueryProgress = true;
20944					$http.get(Routing.generate('api_entities_get_token_users'))
20945						.then(function(response) {
20946							response.data.forEach(function(item) {
20947								item.selected = false;
20948								list.push(item);
20949							});
20950
20951							firstListQuery = false;
20952							listQueryProgress = false;
20953						})
20954						.catch(function(response) {
20955							$log.error(response);
20956							listQueryProgress = false;
20957						});
20958				}
20959
20960				return list;
20961			}
20962		});
20963	}]);
20964
20965},{}],228:[function(require,module,exports){
20966'use strict';
20967
20968angular.module('far.models.user', [])
20969    .service('User', ["$log", "$http", function ($log, $http) {
20970        var list = [],
20971            firstListQuery = true,
20972            listQueryProgress = false;
20973
20974        Object.defineProperty(this, 'list', {
20975            get: function () {
20976                if (firstListQuery && !listQueryProgress) {
20977                    listQueryProgress = true;
20978
20979                    $http.get(Routing.generate(''))
20980                        .then(function (response) {
20981                            response.data.forEach(function (routeData) {
20982                                list.push(new User(routeData));
20983                            });
20984
20985                            firstListQuery = false;
20986                            listQueryProgress = false;
20987                        }, function errorCallback(response) {
20988                            listQueryProgress = false;
20989                            $log.error(response);
20990                        });
20991                }
20992
20993                return list;
20994            }
20995        });
20996
20997        this.new = function (userData) {
20998            return new User(userData);
20999        };
21000
21001        this.delete = function (route, callback) {
21002            return $http.delete(Routing.generate('api_entities_delete_user', {user: route.id}))
21003                .then(function () {
21004                    route = null;
21005
21006                    if (typeof callback == 'function') {
21007                        callback();
21008                    }
21009                }, function errorCallback(response) {
21010                    $log.error(response);
21011                });
21012        };
21013
21014        this.restore = function (route) {
21015            return $http.patch(Routing.generate('api_entities_patch_user', {id: route.id}))
21016                .then(function () {
21017                    return route = null;
21018                }, function errorCallback(response) {
21019                    $log.error(response);
21020                });
21021        };
21022
21023        this.get = function (routeId, callback) {
21024            var route = new User({});
21025
21026            $http.get(Routing.generate('api_entities_get_user', {user: routeId}))
21027                .then(function (response) {
21028                    route.update(response.data);
21029
21030                    if (typeof callback == 'function') {
21031                        callback(route);
21032                    }
21033                }, function errorCallback(response) {
21034                    $log.error(response);
21035                });
21036
21037            return route;
21038        };
21039
21040        function User(userData) {
21041            angular.merge(this, userData);
21042
21043            Object.defineProperty(this, 'update', {
21044                enumerable: false,
21045                get: function () {
21046                    return function (userData) {
21047                        angular.merge(this, userData);
21048
21049                        return this;
21050                    }
21051                }
21052            });
21053
21054            Object.defineProperty(this, 'save', {
21055                enumerable: false,
21056                get: function () {
21057                    return function () {
21058                        var method = this.id ? 'put' : 'post',
21059                            url = this.id ?
21060                                Routing.generate('api_entities_put_user', {user: this.id}) :
21061                                Routing.generate('api_entities_post_user');
21062
21063                        // TODO: Грязный хак
21064                        var data = angular.merge({}, this);
21065
21066                        var objectToId = [
21067                            'enabled',
21068                            'gender',
21069                            'country',
21070                            'qualification',
21071                            'instructor_category',
21072                            'conductor_category',
21073                            'avatar',
21074                            'club',
21075                            'club_position',
21076                            'club_other',
21077                            'alpclub',
21078                            'alpclub_position'
21079                        ];
21080
21081                        for ( var key in objectToId ) {
21082                            var dataName = objectToId[ key ];
21083
21084                            if ( angular.isObject( data[ dataName ] ) ) {
21085                                data[ dataName ] = data[ dataName ].id;
21086                            }
21087                        }
21088
21089                        var objectToName = [
21090                            'region',
21091                            'city'
21092                        ];
21093
21094                        for ( var key in objectToName ) {
21095                            var dataName = objectToName[ key ];
21096
21097                            if ( angular.isObject( data[ dataName ] ) ) {
21098                                data[ dataName ] = data[ dataName ].name;
21099                            }
21100                        }
21101
21102                        data.user_awards = new Array();
21103
21104                        if ( angular.isObject( data.awards ) ) {
21105                            for ( var systemName in data.awards ) {
21106                                var awards = data.awards[ systemName ];
21107
21108                                if ( angular.isArray( awards ) ) {
21109                                    for ( var key in awards ) {
21110                                        if ( angular.isObject( awards[ key].status ) ) {
21111                                            data.user_awards.push({
21112                                                status: awards[ key].status.id,
21113                                                type: awards[ key].type,
21114                                                year: awards[ key].year,
21115                                                user: data.id
21116                                            });
21117                                        }
21118                                    }
21119                                }
21120                            }
21121                        }
21122
21123                        /*['instructor_period_start', 'instructor_period_end', 'birthday', 'member_date_end'].forEach(function(field){
21124                            if (data[field]) {
21125                                data[field] = data[field].substr(0, 10).replace('T', ' ');
21126                            }
21127                        });*/
21128
21129                        return $http[method](url, data);
21130                    }
21131                }
21132            });
21133        }
21134    }]);
21135
21136},{}],229:[function(require,module,exports){
21137/**
21138 * Created by Phatbass on 21/02/16.
21139 */
21140
21141'use strict';
21142
21143// TODO: Add all urls
21144angular.module('far.models.userAchievements', [])
21145    .service('userAchievements', ["$log", "$http", function ($log, $http) {
21146        var list = [];
21147
21148        Object.defineProperty(this, 'list', {
21149            get: function () {
21150                $http.get(Routing.generate('api_get_user_achievement_type_list'))
21151                    .then(function (response) {
21152                        response.data.forEach(function (routeData) {
21153                            list.push({
21154                                id: routeData.id,
21155                                name: routeData.name
21156                            });
21157                        });
21158                    }, function errorCallback(response) {
21159                        $log.error(response);
21160                    });
21161
21162                return list;
21163            }
21164        });
21165    }]);
21166
21167},{}],230:[function(require,module,exports){
21168/**
21169 * Created by Phatbass on 21/02/16.
21170 */
21171
21172'use strict';
21173
21174angular.module('far.models.userAward', [])
21175    .service('userAward', ["$log", "$http", function ($log, $http) {
21176        var status = [],
21177            statusGet = false;
21178
21179        Object.defineProperty(this, 'status', {
21180            get: function () {
21181                if (statusGet == false) {
21182                    statusGet = true;
21183
21184                    $http.get(Routing.generate('api_get_user_award_status'))
21185                        .then(function (response) {
21186                            response.data.forEach(function (routeData) {
21187                                status.push(routeData);
21188                            });
21189
21190                            self.statusLoad = true;
21191                        }, function errorCallback(response) {
21192                            $log.error(response);
21193                        });
21194                }
21195
21196                return status;
21197            }
21198        });
21199    }]);
21200
21201},{}],231:[function(require,module,exports){
21202/**
21203 * Created by Phatbass on 21/02/16.
21204 */
21205
21206'use strict';
21207
21208angular.module('far.models.userClub', [])
21209    .service('userClub', ["$log", "$http", function ($log, $http) {
21210        var list = [],
21211            position = [],
21212            positionList = [],
21213            isRequest = false;
21214
21215        Object.defineProperty(this, 'list', {
21216            get: function () {
21217                $http.get(Routing.generate('api_get_user_clubs'))
21218                    .then(function (response) {
21219                        response.data.forEach(function (routeData) {
21220                            list.push(routeData);
21221                        });
21222                    }, function errorCallback(response) {
21223                        $log.error(response);
21224                    });
21225
21226                return list;
21227            }
21228        });
21229
21230        Object.defineProperty(this, 'position', {
21231            get: function () {
21232                $http.get(Routing.generate('api_get_user_club_positions'))
21233                    .then(function (response) {
21234                        response.data.forEach(function (routeData) {
21235                            position.push(routeData);
21236                        });
21237                    }, function errorCallback(response) {
21238                        $log.error(response);
21239                    });
21240
21241                return position;
21242            }
21243        });
21244
21245        Object.defineProperty(this, 'positionList', {
21246            get: function () {
21247                if (!positionList.length && !isRequest) {
21248                    isRequest = true;
21249                    $http.get(Routing.generate('api_get_user_club_positions'))
21250                        .then(function (response) {
21251                            response.data.forEach(function (routeData) {
21252                                positionList.push(routeData);
21253                            });
21254                            isRequest = false;
21255                        }, function errorCallback(response) {
21256                            isRequest = false;
21257                            $log.error(response);
21258                        });
21259                }
21260                return positionList;
21261            }
21262        });
21263    }]);
21264
21265},{}],232:[function(require,module,exports){
21266'use strict';
21267
21268angular.module('far.models.userMembership', [])
21269    .service('userMembership', ["$log", "$http", function ($log, $http) {
21270        this.new = function (userData) {
21271            return new User(userData);
21272        };
21273
21274        this.get = function (routeId, callback) {
21275            var route = new User({});
21276
21277            $http.get(Routing.generate('api_entities_get_user', {user: routeId}))
21278                .then(function (response) {
21279                    route.update(response.data);
21280
21281                    if (typeof callback == 'function') {
21282                        callback(route);
21283                    }
21284                }, function errorCallback(response) {
21285                    $log.error(response);
21286                });
21287
21288            return route;
21289        };
21290
21291        function User(userData) {
21292            angular.merge(this, userData);
21293
21294            Object.defineProperty(this, 'update', {
21295                enumerable: false,
21296                get: function () {
21297                    return function (userData) {
21298                        angular.merge(this, userData);
21299
21300                        return this;
21301                    }
21302                }
21303            });
21304
21305            Object.defineProperty(this, 'save', {
21306                enumerable: false,
21307                get: function () {
21308                    return function () {
21309                        // TODO: Грязный хак
21310                        var data = angular.merge({}, this);
21311
21312                        var objectToId = [
21313                            'country',
21314                        ];
21315
21316                        for ( var key in objectToId ) {
21317                            var dataName = objectToId[ key ];
21318
21319                            if ( angular.isObject( data[ dataName ] ) ) {
21320                                data[ dataName ] = data[ dataName ].id;
21321                            }
21322                        }
21323
21324                        var objectToName = [
21325                            'region',
21326                            'city'
21327                        ];
21328
21329                        for ( var key in objectToName ) {
21330                            var dataName = objectToName[ key ];
21331
21332                            if ( angular.isObject( data[ dataName ] ) ) {
21333                                data[ dataName ] = data[ dataName ].name;
21334                            }
21335                        }
21336
21337                        return $http.put(Routing.generate('api_entities_put_user_membership', {user: this.id}), data);
21338                    }
21339                }
21340            });
21341        }
21342    }]);
21343
21344},{}],233:[function(require,module,exports){
21345/**
21346 * Created by Phatbass on 21/02/16.
21347 */
21348
21349'use strict';
21350
21351// TODO: Add all urls
21352angular.module('far.models.userQualification', [])
21353    .service('userQualification', ["$log", "$http", function ($log, $http) {
21354        var list = [];
21355        var listLoaded = false;
21356
21357        Object.defineProperty(this, 'list', {
21358            get: function () {
21359                return this.getList();
21360            }
21361        });
21362
21363        this.getList = function (callback) {
21364
21365            if (listLoaded) {
21366                return list;
21367            }
21368
21369            $http.get(Routing.generate('api_get_user_qualifications'))
21370                .then(function (response) {
21371                    response.data.forEach(function (routeData) {
21372                        list.push(routeData);
21373                    });
21374                    listLoaded = true;
21375                    if (typeof callback == 'function') {
21376                        callback();
21377                    }
21378                }, function errorCallback(response) {
21379                    $log.error(response);
21380                });
21381
21382            return list;
21383        };
21384
21385
21386    }]);
21387
21388},{}],234:[function(require,module,exports){
21389'use strict';
21390
21391require('../../helpers/guid/guid.service');
21392
21393angular.module('far.models.userRelation', ['far.helpers.guid'])
21394.service('UserRelation', ["guid", function(guid) {
21395
21396    this.new = function(userData) {
21397      return new UserRelation(userData);
21398    };
21399
21400    this.newUndefined = function(userRelation, userType) {
21401      var userData = {};
21402      userData[userRelation] = userType;
21403
21404      return new UserRelation(userData);
21405    };
21406
21407    function UserRelation(userData) {
21408      this.user = undefined;
21409
21410      Object.defineProperty(this, 'uniqId', {
21411        enumerable: false,
21412        writable: false,
21413        value: guid()
21414      });
21415
21416      Object.defineProperty(this, 'relation', {
21417        enumerable: false,
21418        writable: false,
21419        value: Object.keys(userData).filter(function(userKey) {
21420          return ['user', 'id'].indexOf(userKey) == -1;
21421        })[0]
21422      });
21423
21424      angular.merge(this, userData);
21425    }
21426
21427    UserRelation.prototype.toJSON = function() {
21428      if (!this.user || !this.user.id) {
21429        return undefined;
21430      }
21431
21432      var jsonData = {
21433        user: this.user.id
21434      };
21435      jsonData[this.relation] = this[this.relation].id;
21436      if (this.id) {
21437        jsonData.id = this.id;
21438      }
21439
21440      return jsonData;
21441    };
21442}]);
21443
21444},{"../../helpers/guid/guid.service":165}],235:[function(require,module,exports){
21445'use strict';
21446
21447angular.module('far.models.userSendings', [])
21448    .service('userSendings', ["$log", "$http", "$filter", function ($log, $http, $filter) {
21449
21450        this.get = function (routeId, callback) {
21451
21452            var route = new UserSendings();
21453
21454            $http.get(Routing.generate('api_entities_get_user_sendings', {user: routeId}))
21455                .then(function (response) {
21456                    route.update(response.data);
21457
21458                    if (typeof callback == 'function') {
21459                        callback(route);
21460                    }
21461
21462                }, function errorCallback(response) {
21463                    $log.error(response);
21464                });
21465
21466            return route;
21467        };
21468
21469        class UserSendings {
21470
21471            constructor(userData = null)
21472            {
21473                this.id = null;
21474                this.is_member_card_received = false;
21475                this.is_member_card_sent = false;
21476                this.member_card_and_sticker_request_enabled = false;
21477                this.sticker_request_enabled = false;
21478                this.member_card_received = null;
21479                this.member_card_sent = null;
21480                this.send_member_card_and_sticker = false;
21481                this.send_sticker = false;
21482
21483                if (userData) {
21484                    this.update(userData);
21485                }
21486            }
21487
21488            update(userData)
21489            {
21490                var self = this;
21491
21492                angular.merge(self, userData);
21493
21494                if (userData.hasOwnProperty('member_card_sent')) {
21495                    self.member_card_sent = userData.member_card_sent ? $filter('date')(new Date(userData.member_card_sent), 'dd.MM.yyyy') : null;
21496                    self.is_member_card_sent = userData.member_card_sent ? true : false;
21497                }
21498
21499                if (userData.hasOwnProperty('member_card_received')) {
21500                    self.is_member_card_received = userData.member_card_received ? true : false;
21501                }
21502
21503                if (this.is_member_card_received || this.send_member_card_and_sticker) {
21504                    this.member_card_and_sticker_request_enabled = false;
21505                } else {
21506                    this.member_card_and_sticker_request_enabled = true;
21507                }
21508
21509                this.sticker_request_enabled = !this.send_sticker;
21510
21511                return this;
21512            }
21513
21514            saveSendMemberCardAndSticker(callback)
21515            {
21516                var self = this;
21517                $http.patch(Routing.generate('api_entities_patch_user_send_member_card_and_sticker', {user : this.id }), {
21518                    send_member_card_and_sticker : self.send_member_card_and_sticker
21519                }).then(function(response) {
21520                    self.update(response.data);
21521                    if (typeof callback == 'function') {
21522                        callback(self);
21523                    }
21524                }, function errorCallback(response) {
21525                    $log.error(response);
21526                });
21527            }
21528
21529            saveSendSticker(callback)
21530            {
21531                var self = this;
21532                $http.patch(Routing.generate('api_entities_patch_user_send_sticker', {user : this.id }), {
21533                    send_sticker : self.send_sticker
21534                }).then(function(response) {
21535                    self.update(response.data);
21536                    if (typeof callback == 'function') {
21537                        callback(self);
21538                    }
21539                }, function errorCallback(response) {
21540                    $log.error(response);
21541                });
21542            }
21543
21544            saveMemberCardSent(callback)
21545            {
21546                var self = this;
21547                $http.patch(Routing.generate('api_entities_patch_user_member_card_sent', {user : this.id }), {
21548                    is_member_card_sent : self.is_member_card_sent
21549                }).then(function(response) {
21550                    self.update(response.data);
21551                    if (typeof callback == 'function') {
21552                        callback(self);
21553                    }
21554                }, function errorCallback(response) {
21555                    $log.error(response);
21556                });
21557            }
21558
21559            saveMemberCardReceived(callback)
21560            {
21561                var self = this;
21562                $http.patch(Routing.generate('api_entities_patch_user_member_card_received', {user : this.id }), {
21563                    is_member_card_received : self.is_member_card_received
21564                }).then(function(response) {
21565                    self.update(response.data);
21566                    if (typeof callback == 'function') {
21567                        callback(self);
21568                    }
21569                }, function errorCallback(response) {
21570                    $log.error(response);
21571                });
21572            };
21573
21574
21575        }
21576
21577
21578
21579
21580
21581
21582    }]);
21583
21584},{}],236:[function(require,module,exports){
21585require('./carousel.module');
21586
21587},{"./carousel.module":237}],237:[function(require,module,exports){
21588'use strict';
21589
21590angular.module('far.carousel', [])
21591    .directive('elCarousel', ["$window", "$interval", "$compile", "$timeout", function ($window, $interval, $compile, $timeout) {
21592        return {
21593            scope: {
21594                items: '=elCarousel',
21595                interval: '=moveInterval',
21596                timeout: '@?'
21597            },
21598            restrict: 'A',
21599            templateUrl: function(element, attrs) {
21600                return attrs.templateUrl;
21601            },
21602            link: function (scope, elem) {
21603                elem.addClass('el-carousel');
21604
21605                scope.prev = function() {
21606                    stopCarousel();
21607
21608                    var firstElem = scope.items.pop();
21609                    scope.items.unshift(firstElem);
21610                }
21611
21612                scope.next = function() {
21613                    stopCarousel();
21614                    moveItems();
21615                }
21616
21617                function moveItems() {
21618                    var lastElem = scope.items.shift();
21619                    scope.items.push(lastElem);
21620                }
21621
21622                var moveInterval, interval = scope.interval*1000;
21623
21624                if (scope.items.length <= 2) {
21625                    elem.on('mouseleave', function() {
21626                        console.log('leave');
21627                        runCarousel();
21628                    });
21629                    elem.on('mouseenter', function() {
21630                        console.log('enter');
21631                        stopCarousel();
21632                    });
21633                    
21634                    if (scope.timeout) {
21635                        $timeout(function() {
21636                            runCarousel();        
21637                        }, scope.timeout);
21638                    } else {
21639                        runCarousel();            
21640                    }    
21641                }
21642                
21643                angular.element($window).bind('blur', stopCarousel);
21644
21645                function stopCarousel() {
21646                    $interval.cancel(moveInterval);
21647                }
21648
21649                angular.element($window).bind('focus', runCarousel);
21650
21651                function runCarousel() {
21652                    moveInterval = $interval(moveItems, interval);
21653                }
21654
21655                elem.bind('$destroy', function () {
21656                    $interval.cancel(moveInterval);
21657                    angular.element($window).unbind('blur', stopCarousel);
21658                    angular.element($window).unbind('focus', runCarousel);
21659                });
21660            }
21661        };
21662    }]);
21663
21664},{}],238:[function(require,module,exports){
21665(function() {
21666    'use strict';
21667
21668    /**
21669     * usage: <textarea ng-model="content" redactor></textarea>
21670     *
21671     *    additional options:
21672     *      redactor: hash (pass in a redactor options hash)
21673     *
21674     */
21675
21676    var redactorOptions = {};
21677
21678    angular.module('cp.redactor', [])
21679        .constant('redactorOptions', redactorOptions)
21680        .directive('redactor', ['$timeout', function($timeout) {
21681            return {
21682                restrict: 'A',
21683                require: 'ngModel',
21684                link: function(scope, element, attrs, ngModel) {
21685
21686                    // Expose scope var with loaded state of Redactor
21687                    scope.redactorLoaded = false;
21688
21689                    var updateModel = function updateModel(value) {
21690                            $timeout(function() {
21691                                scope.$apply(function() {
21692                                    ngModel.$setViewValue(value);
21693                                });
21694                            });
21695                        },
21696                        options = {
21697                            lang: 'ru',
21698                            replaceDivs: false,
21699                            plugins: ['table', 'fontcolor'],
21700                            changeCallback: updateModel,
21701                            minHeight: 200,
21702                            imageUpload: Routing.generate('api_upload_post_image_from_redactor'),
21703                            imageUploadParam: 'image',
21704                            imageDeleteCallback: function(url, image) {
21705                                console.log(url)
21706                            },
21707                            fileUpload: Routing.generate('api_upload_post_file_from_redactor'),
21708                            modalOpenedCallback: function(name) {
21709                                if (name == 'imageEdit') {
21710                                    var $image = $(this.observe.image);
21711
21712                                    var width = $image.width(),
21713                                        height = $image.height(),
21714                                        inputWidth = $("#redactor-image-width"),
21715                                        inputHeight = $("#redactor-image-height");
21716
21717                                    inputWidth.val(width);
21718                                    inputHeight.val(height);
21719
21720                                    $("#redactor-image-width, #redactor-image-height").keyup(function(e) {
21721                                        if (/\D/g.test(this.value)) {
21722                                            this.value = this.value.replace(/\D/g, '');
21723                                        }
21724
21725                                        if (this.id == 'redactor-image-width') {
21726                                            inputHeight.val(Math.round(this.value*(height/width)));
21727                                        } else {
21728                                            inputWidth.val(Math.round(this.value*(width/height)));
21729                                        }
21730                                    });
21731
21732                                    this.image.buttonSave.on('click', $.proxy(function() {
21733                                        $image.css('width', inputWidth.val());
21734                                        $image.css('height', inputHeight.val());
21735
21736                                        this.code.sync();
21737                                    }, this));
21738                                }
21739                            }
21740                        },
21741                        additionalOptions = attrs.redactor ?
21742                            scope.$eval(attrs.redactor) : {},
21743                        editor;
21744                    angular.extend(options, redactorOptions, additionalOptions);
21745                    
21746                    // put in timeout to avoid $digest collision.  call render()
21747                    // to set the initial value.
21748                    $timeout(function() {
21749                        editor = element.redactor(options);
21750                        ngModel.$render();
21751                    });
21752
21753                    ngModel.$render = function() {
21754                        if(angular.isDefined(editor)) {
21755                            $timeout(function() {
21756                                element.redactor('code.set', ngModel.$viewValue || '');
21757                                scope.redactorLoaded = true;
21758                            });
21759                        }
21760                    };
21761                }
21762            };
21763        }]);
21764})();
21765
21766},{}],239:[function(require,module,exports){
21767'use strict';
21768
21769angular.module('dekky.forms')
21770    .directive('formErrors', function () {
21771        return {
21772            restrict: 'A',
21773            link: function (scope, element, attributes) {
21774                var $element = angular.element(element);
21775
21776                $element.bind('submit', function (e) {
21777                    e.preventDefault();
21778
21779                    if (scope[attributes.name].$invalid) {
21780                        window.scrollTo(0, $element.find('.ng-invalid').first().offset().top - 15);
21781                        $element.find('.ng-error').removeClass('ng-error');
21782                        $element.find('.ng-invalid').addClass('ng-error');
21783                        return false;
21784                    }
21785                });
21786            }
21787        }
21788    });
21789
21790},{}],240:[function(require,module,exports){
21791'use strict';
21792
21793angular.module('dekky.forms')
21794	.directive('formRow', ["$q", "$http", "$templateCache", "$compile", function($q, $http, $templateCache, $compile) {
21795		return {
21796			restrict: 'AE',
21797			require: 'ngModel',
21798			replace: true,
21799			scope: {
21800				field: '=',
21801				model: '=ngModel',
21802				fieldIndex: '=',
21803                disabled: '=?ngDisabled'
21804			},
21805			link: function(scope, element, attr) {
21806				var theme = scope.field.form.config.theme,
21807					template = attr.templateUrl ? attr.templateUrl :  theme + '/row.html';
21808
21809				function getTemplateUrl() {
21810					return $q.when(template);
21811				}
21812
21813				function loadTemplate(template) {
21814					return $http.get(template, {cache: $templateCache})
21815							.then(function(response) {
21816								return angular.element(response.data);
21817							});
21818				}
21819
21820				function compileTemplate(template) {
21821					element.append(template);
21822
21823					return $compile(element.contents())(scope);
21824				}
21825
21826				getTemplateUrl()
21827					.then(loadTemplate)
21828					.then(compileTemplate);
21829			}
21830		}
21831	}]);
21832
21833},{}],241:[function(require,module,exports){
21834'use strict';
21835
21836angular.module('dekky.forms')
21837.directive('formWidget', ["$compile", "$log", "$templateCache", "$http", "$q", "formsUtils", "$interpolate", function($compile, $log, $templateCache, $http, $q, formsUtils, $interpolate) {
21838	return {
21839		restrict: 'AE',
21840		require: 'ngModel',
21841		scope: {
21842			field: '=',
21843			model: '=ngModel',
21844			fieldIndex: '=',
21845			fieldData: '=',
21846            disabled: '=?ngDisabled'
21847		},
21848		link: function(scope, element, attrs, controller) {
21849			var theme = scope.field.form.config.theme;
21850
21851			scope.validators = scope.field.validators;
21852			scope.options = scope.field.options;
21853			scope.field.model = scope.model;
21854			scope.disabled = scope.disabled || false;
21855
21856
21857
21858			function getTemplateUrl(type) {
21859				var template = attrs.templateUrl ? attrs.templateUrl :  theme + '/fields/' + type + '.html';
21860
21861				return $q.when(template);
21862			}
21863
21864			function loadTemplate(template) {
21865				return $http.get(template, {cache: $templateCache})
21866					.then(function(response) {
21867						return angular.element(response.data);
21868					});
21869			}
21870
21871			function setValidators(templateElement) {
21872				angular.forEach(scope.validators, function(validator, validatorName) {
21873					var validatorValue;
21874
21875					if (angular.isObject(validator)) {
21876						validatorValue = 'validators.' + validatorName;
21877					} else if (angular.isFunction(validator)) {
21878						validatorValue = 'validators.' + validatorName + '()';
21879					} else {
21880						validatorValue = validator;
21881					}
21882
21883					angular.element(templateElement[0]).attr(formsUtils.camelToDash(validatorName), validatorValue);
21884				});
21885
21886				return $q.when(templateElement);
21887			}
21888
21889			function setOptions(templateElement) {
21890				angular.forEach(scope.options, function(option, optionName) {
21891					var optionValue;
21892
21893					if (angular.isObject(option)) {
21894						optionValue = 'options.' + optionName;
21895					} else if (angular.isFunction(option)) {
21896						optionValue = 'options.' + optionName + '()';
21897					} else {
21898						optionValue = option;
21899					}
21900
21901					if(optionName == 'defaultOption') {
21902						var defaultOptionTemplate;
21903						scope.defaultOptionText = option || 'Select...';
21904						defaultOptionTemplate = '<option value="">{{defaultOptionText}}</option>';
21905						angular.element(templateElement[0]).prepend($interpolate(defaultOptionTemplate)(scope));
21906					} else if ( scope.field.type == 'checkbox' && templateElement[0].tagName.toLowerCase() == 'label' ) {
21907						angular.element(templateElement.children('input')[0]).attr(formsUtils.camelToDash(optionName), optionValue);
21908					} else {
21909						angular.element(templateElement[0]).attr(formsUtils.camelToDash(optionName), optionValue);
21910					}
21911				});
21912
21913				return $q.when(templateElement);
21914			}
21915
21916			function compileTemplate(template) {
21917				element.append(template);
21918
21919				return $compile(element.contents())(scope);
21920			}
21921
21922			function linkField(template) {
21923				return scope.field.link(template, scope, element, attrs, controller);
21924			}
21925
21926			getTemplateUrl(scope.field.type)
21927				.then(loadTemplate)
21928				.then(setOptions)
21929				.then(setValidators)
21930				.then(linkField)
21931				.then(compileTemplate);
21932		}
21933	}
21934}]);
21935
21936},{}],242:[function(require,module,exports){
21937'use strict';
21938
21939var dd = angular.module('rorymadden.date-dropdowns', []);
21940
21941dd.factory('rsmdateutils', function () {
21942	var that = this,
21943		dayRange = [1, 31],
21944		months = [
21945			'Январь',
21946			'Февраль',
21947			'Март',
21948			'Апрель',
21949			'Май',
21950			'Июнь',
21951			'Июль',
21952			'Август',
21953			'Сентябрь',
21954			'Октябрь',
21955			'Ноябрь',
21956			'Декабрь'
21957		];
21958
21959	function changeDate (date) {
21960		if(date.day > 28) {
21961			date.day--;
21962			return date;
21963		} else if (date.month > 11) {
21964			date.day = 31;
21965			date.month--;
21966			return date;
21967		}
21968	};
21969
21970	return {
21971		checkDate: function (date) {
21972			var d;
21973			if (!date.day || date.month === null || date.month === undefined || !date.year) return false;
21974
21975			d = new Date(Date.UTC(date.year, date.month, date.day));
21976
21977			if (d && (d.getMonth() === date.month && d.getDate() === Number(date.day))) {
21978				return d;
21979			}
21980
21981			return this.checkDate(changeDate(date));
21982		},
21983		days: (function () {
21984			var days = [];
21985			while (dayRange[0] <= dayRange[1]) {
21986				days.push(dayRange[0]++);
21987			}
21988			return days;
21989		}()),
21990		months: (function () {
21991			var lst = [],
21992				mLen = months.length;
21993
21994			for (var i = 0; i < mLen; i++) {
21995				lst.push({
21996					value: i,
21997					name: months[i]
21998				});
21999			}
22000			return lst;
22001		}())
22002	};
22003});
22004
22005dd.directive('rsmdatedropdowns', ['rsmdateutils', function (rsmdateutils) {
22006	return {
22007		restrict: 'A',
22008		replace: true,
22009		require: 'ngModel',
22010		scope: {
22011			model: '=ngModel'
22012		},
22013		controller: ['$scope', 'rsmdateutils', function ($scope, rsmDateUtils) {
22014			$scope.days = rsmDateUtils.days;
22015			$scope.months = rsmDateUtils.months;
22016
22017			$scope.dateFields = {};
22018
22019			$scope.dateFields.day = new Date($scope.model).getUTCDate();
22020			$scope.dateFields.month = new Date($scope.model).getUTCMonth();
22021			$scope.dateFields.year = new Date($scope.model).getUTCFullYear();
22022
22023			// Initialize with current date (if set)
22024			$scope.$watch('model', function (newDate) {
22025				if(newDate) {
22026					$scope.dateFields.day = new Date(newDate).getUTCDate();
22027					$scope.dateFields.month = new Date(newDate).getUTCMonth();
22028					$scope.dateFields.year = new Date(newDate).getUTCFullYear();
22029				}
22030			});
22031
22032			$scope.checkDate = function () {
22033				var date = rsmDateUtils.checkDate($scope.dateFields);
22034				$scope.ctrl.$setTouched();
22035				if (date) {
22036					$scope.model = date;
22037				} else {
22038					$scope.model = undefined;
22039				}
22040			};
22041		}],
22042		template:
22043		'<div class="form-date">' +
22044		'    <select class="form__item form__item_select form-date__day" name="dateFields.day" data-ng-model="dateFields.day" placeholder="Дата" ng-options="day for day in days" ng-change="checkDate()" ng-disabled="disableFields">' +
22045				'<option value="" selected="">День</option>' +
22046		'    </select>' +
22047		'    <select class="form__item form__item_select form-date__month" name="dateFields.month" data-ng-model="dateFields.month" placeholder="Месяц" ng-options="month.value as month.name for month in months" value="{{ dateField.month }}" ng-change="checkDate()" ng-disabled="disableFields">' +
22048				'<option value="" selected="">Месяц</option>' +
22049		'    </select>' +
22050		'    <input class="form__item form-date__year" type="text" name="dateFields.year" data-ng-model="dateFields.year" placeholder="Год" ng-blur="checkDate()" ng-disabled="disableFields" maxlength="4" numeric-only>' +
22051		'</div>',
22052		link: function (scope, element, attrs, ctrl) {
22053			var currentYear = parseInt(attrs.startingYear, 10) || new Date().getFullYear(),
22054				numYears = parseInt(attrs.numYears,10) || 100,
22055				oldestYear = currentYear - numYears,
22056				overridable = [
22057					'dayDivClass',
22058					'dayClass',
22059					'monthDivClass',
22060					'monthClass',
22061					'yearDivClass',
22062					'yearClass'
22063				];
22064
22065			scope.years = [];
22066			scope.yearText = attrs.yearText ? true : false;
22067			scope.ctrl = ctrl;
22068
22069			if (attrs.ngDisabled) {
22070				scope.$parent.$watch(attrs.ngDisabled, function (newVal) {
22071					scope.disableFields = newVal;
22072				});
22073			}
22074
22075			//if (attrs.required) {
22076			//	ctrl.$parsers.push(function (value) {
22077			//		angular.forEach(required, function (elem) {
22078			//			if (!angular.isNumber(elem)) {
22079			//				ctrl.$setValidity('required', false);
22080			//			}
22081			//		});
22082			//		ctrl.$setValidity('required', true);
22083			//	});
22084			//}
22085
22086			for (var i = currentYear; i >= oldestYear; i--) {
22087				scope.years.push(i);
22088			}
22089
22090			(function () {
22091				var oLen = overridable.length,
22092					oCurrent,
22093					childEle;
22094				while (oLen--) {
22095					oCurrent = overridable[oLen];
22096					childEle = element[0].children[Math.floor(oLen / 2)];
22097
22098					if (oLen % 2 && oLen != 2) {
22099						childEle = childEle.children[0];
22100					}
22101
22102					if (attrs[oCurrent]) {
22103						angular.element(childEle).attr('class', attrs[oCurrent]);
22104					}
22105				}
22106			}());
22107		}
22108	};
22109}]);
22110
22111},{}],243:[function(require,module,exports){
22112'use strict';
22113
22114angular.module('dekky.forms.uiSelect', [])
22115.directive('uiSelectManualClear', ["$rootScope", function($rootScope) {
22116   return {
22117       restrict: 'A',
22118       require: 'uiSelect',
22119       link: function(scope, element, attrs, $select) {
22120           var syntheticEvent = {
22121               stopPropagation: function() {}
22122           };
22123
22124           $rootScope.$on(attrs.uiSelectManualClear, function(event) {
22125               $select.clear(syntheticEvent);
22126               event.stopPropagation();
22127           });
22128       }
22129   }
22130}]);
22131
22132},{}],244:[function(require,module,exports){
22133require('./forms.module');
22134
22135require('./models/formFactory');
22136require('./models/fieldFactory');
22137
22138require('./directives/form-widget/form-widget');
22139require('./directives/form-widget/form-row');
22140require('./directives/form-widget/form-errors');
22141
22142},{"./directives/form-widget/form-errors":239,"./directives/form-widget/form-row":240,"./directives/form-widget/form-widget":241,"./forms.module":245,"./models/fieldFactory":246,"./models/formFactory":270}],245:[function(require,module,exports){
22143'use strict';
22144
22145require('./directives/rorymadden.date-dropdowns');
22146require('./directives/cp.redactor');
22147require('./directives/ui-select-manual-clear');
22148
22149require('./services/utils.service');
22150require('./services/autocomplete.service');
22151require('./services/softdeleteable.service');
22152require('./services/hideshowpassword.service');
22153require('./services/fileUploadFilters.service');
22154require('./services/http.service');
22155
22156// Fields
22157require('./models/fields/Text');
22158require('./models/fields/Select');
22159require('./models/fields/SelectObject');
22160require('./models/fields/Collection');
22161require('./models/fields/DateDropdowns');
22162require('./models/fields/Checkbox');
22163require('./models/fields/CheckboxCollection');
22164require('./models/fields/FileUpload');
22165require('./models/fields/ImageUpload');
22166require('./models/fields/MountainAreaSelect');
22167require('./models/fields/MountainPeakSelect');
22168require('./models/fields/UserSelect');
22169require('./models/fields/Hidden');
22170require('./models/fields/Slider');
22171require('./models/fields/Range');
22172require('./models/fields/RadioCollection');
22173require('./models/fields/Number');
22174require('./models/fields/Textarea');
22175require('./models/fields/UiSelect');
22176require('./models/fields/UiDatepicker');
22177require('./models/fields/UiTypeahead');
22178require('./models/fields/Url');
22179
22180// Validators
22181require('./validators/collectionMinlength');
22182require('./validators/collectionMaxlength');
22183require('./validators/numericOnly');
22184require('./validators/emailOnly');
22185require('./validators/urlOnly');
22186
22187// Themes
22188require('./themes/bootstrap/bootstrap');
22189require('./themes/far/far');
22190
22191angular.module('dekky.forms', [
22192	'rorymadden.date-dropdowns',
22193	'cp.redactor',
22194	'dekky.forms.uiSelect',
22195	'dekky.forms.utils',
22196	'dekky.forms.autocomplete',
22197	'dekky.forms.softdeleteable',
22198	'dekky.forms.hideShowPassword',
22199	'dekky.forms.fileUploadFilters',
22200	'dekky.forms.http',
22201
22202	'dekky.forms.fields.text',
22203	'dekky.forms.fields.select',
22204	'dekky.forms.fields.selectObject',
22205	'dekky.forms.fields.collection',
22206	'dekky.forms.fields.dateDropdowns',
22207	'dekky.forms.fields.checkbox',
22208	'dekky.forms.fields.checkboxCollection',
22209	'dekky.forms.fields.fileUpload',
22210	'dekky.forms.fields.imageUpload',
22211	'dekky.forms.fields.mountainAreaSelect',
22212	'dekky.forms.fields.mountainPeakSelect',
22213	'dekky.forms.fields.userSelect',
22214	'dekky.forms.fields.hidden',
22215	'dekky.forms.fields.slider',
22216	'dekky.forms.fields.range',
22217	'dekky.forms.fields.radioCollection',
22218	'dekky.forms.fields.number',
22219	'dekky.forms.fields.textarea',
22220	'dekky.forms.fields.uiSelect',
22221	'dekky.forms.fields.uiDatepicker',
22222	'dekky.forms.fields.uiTypeahead',
22223	'dekky.forms.fields.url',
22224
22225	//'dekky.forms.validators.collectionMinlength',
22226	'dekky.forms.validators.collectionMaxlength',
22227	'dekky.forms.validators.numericOnly',
22228	'dekky.forms.validators.emailOnly',
22229	'dekky.forms.validators.urlOnly',
22230
22231	'dekky.forms.themes.bootstrap',
22232	'dekky.forms.themes.far'
22233])
22234.value('formsConfig', {
22235	theme: '/dekky.forms/themes/bootstrap'
22236});
22237
22238},{"./directives/cp.redactor":238,"./directives/rorymadden.date-dropdowns":242,"./directives/ui-select-manual-clear":243,"./models/fields/Checkbox":247,"./models/fields/CheckboxCollection":248,"./models/fields/Collection":249,"./models/fields/DateDropdowns":250,"./models/fields/FileUpload":252,"./models/fields/Hidden":253,"./models/fields/ImageUpload":254,"./models/fields/MountainAreaSelect":255,"./models/fields/MountainPeakSelect":256,"./models/fields/Number":257,"./models/fields/RadioCollection":258,"./models/fields/Range":259,"./models/fields/Select":260,"./models/fields/SelectObject":261,"./models/fields/Slider":262,"./models/fields/Text":263,"./models/fields/Textarea":264,"./models/fields/UiDatepicker":265,"./models/fields/UiSelect":266,"./models/fields/UiTypeahead":267,"./models/fields/Url":268,"./models/fields/UserSelect":269,"./services/autocomplete.service":271,"./services/fileUploadFilters.service":272,"./services/hideshowpassword.service":273,"./services/http.service":274,"./services/softdeleteable.service":275,"./services/utils.service":276,"./themes/bootstrap/bootstrap":278,"./themes/far/far":303,"./validators/collectionMaxlength":327,"./validators/collectionMinlength":328,"./validators/emailOnly":329,"./validators/numericOnly":330,"./validators/urlOnly":331}],246:[function(require,module,exports){
22239'use strict';
22240
22241angular.module('dekky.forms')
22242.provider('formField', function() {
22243
22244	this.$get = ["$log", "$injector", function($log, $injector) {
22245		function fieldFactory(name, fieldType, config, additionalParams) {
22246			fieldType = fieldType.charAt(0).toUpperCase() + fieldType.slice(1) + 'Field';
22247
22248			var fieldTypeService = $injector.get(fieldType);
22249
22250			return fieldTypeService(name, config, additionalParams);
22251		}
22252
22253		return fieldFactory;
22254	}];
22255});
22256
22257},{}],247:[function(require,module,exports){
22258'use strict';
22259
22260var Field = require('./Field');
22261
22262angular.module('dekky.forms.fields.checkbox', [])
22263.factory('CheckboxField', function() {
22264	function checkboxFactory(name, options) {
22265		function Checkbox(name, options) {
22266			this.type = 'checkbox';
22267
22268			Field.apply(this, arguments);
22269		}
22270
22271		Checkbox.prototype = Object.create(Field.prototype);
22272
22273		return new Checkbox(name, options);
22274	}
22275
22276	return checkboxFactory;
22277});
22278
22279},{"./Field":251}],248:[function(require,module,exports){
22280'use strict';
22281
22282var Field = require('./Field');
22283
22284require('../../services/utils.service');
22285
22286angular.module('dekky.forms.fields.checkboxCollection', ['dekky.forms.utils'])
22287	.factory('CheckboxCollectionField', ["$log", "$q", "formsUtils", function($log, $q, formsUtils) {
22288		function checkboxCollectionFactory(name, options, items) {
22289			function CheckboxCollection(name, options, items) {
22290				if (!Array.isArray(items)) {
22291					throw new Error('Not items for select');
22292				}
22293				if (angular.isUndefined(options.checkbox)) {
22294					throw new Error('Not options for checkbox');
22295				}
22296				this.type = 'checkboxCollection';
22297				this.items = items;
22298				this.checkbox = options.checkbox;
22299				this.checkboxAttributes = options.checkboxAttributes || {};
22300
22301				Field.apply(this, arguments);
22302			}
22303
22304			CheckboxCollection.prototype = Object.create(Field.prototype);
22305			CheckboxCollection.prototype.link = function(template, scope, element, attrs, controller) {
22306				var that = this,
22307					checkbox = template.find('input');
22308
22309				scope.$watch(function() {
22310					return angular.toJson(that.items);
22311				}, function() {
22312					if (!angular.isArray(controller.$viewValue)) {
22313						controller.$viewValue = [];
22314					}
22315
22316					controller.$viewValue.length = 0;
22317					that.items.forEach(function(item) {
22318						if (item[that.checkbox.model]) {
22319							controller.$viewValue.push(item);
22320						}
22321					});
22322					
22323					controller.$validate();
22324				}, true);
22325
22326				angular.forEach(this.checkboxAttributes, function(value, attr) {
22327					if (angular.isFunction(value)) {
22328						checkbox.attr(formsUtils.camelToDash(attr), 'field.checkboxAttributes.' + attr + '()');
22329					} else {
22330						checkbox.attr(formsUtils.camelToDash(attr), value);
22331					}
22332				});
22333
22334				return $q.when(template);
22335			};
22336
22337			return new CheckboxCollection(name, options, items);
22338		}
22339
22340		return checkboxCollectionFactory;
22341	}]);
22342
22343},{"../../services/utils.service":276,"./Field":251}],249:[function(require,module,exports){
22344'use strict';
22345
22346var Field = require('./Field');
22347
22348angular.module('dekky.forms.fields.collection', [])
22349.factory('CollectionField', ["$log", "$q", function($log, $q) {
22350	function collectionFactory(name, options, childForm) {
22351		function Collection(name, options, childForm) {
22352			this.type = 'collection';
22353
22354			if (!childForm) {
22355				throw new Exception('Undefined child form');
22356			}
22357
22358			this.buttons = angular.merge({
22359				add: 'add',
22360				remove: 'remove',
22361				copy: 'copy'
22362			}, options.buttons);
22363			this.childForm = childForm;
22364			this.doDelete = function(item, model, index) {
22365				model.splice(index, 1);
22366			};
22367			this.ngRepeat = 'item in model track by $index';
22368
22369			Field.apply(this, arguments);
22370		}
22371
22372		Collection.prototype = Object.create(Field.prototype);
22373		Collection.prototype.addItem = function(model) {
22374			var newItem = {};
22375
22376			Object.keys(this.childForm.$fields).forEach(function(key) {
22377				newItem[key] = undefined;
22378			});
22379
22380			model.push(newItem);
22381		};
22382
22383        Collection.prototype.copyItem = function(item, model, index) {
22384            var newItem = angular.copy(item);
22385
22386            model.push(newItem);
22387        };
22388
22389		Collection.prototype.link = function(template) {
22390			var collection = template[0].querySelector('[repeat-collection]');
22391
22392			angular.element(collection).removeAttr('repeat-collection');
22393			angular.element(collection).attr('ng-repeat', this.ngRepeat);
22394
22395			return $q.when(template);
22396		};
22397
22398		return new Collection(name, options, childForm);
22399	}
22400
22401	return collectionFactory;
22402}]);
22403
22404},{"./Field":251}],250:[function(require,module,exports){
22405'use strict';
22406
22407var Field = require('./Field');
22408
22409angular.module('dekky.forms.fields.dateDropdowns', [])
22410	.factory('DateDropdownsField', function() {
22411		function dateDropdownsFactory(name, options) {
22412			function DateDropdowns(name, options) {
22413				options = options || {};
22414
22415				this.uiSelectOptions = options.uiSelectOptions || {};
22416
22417				if (!this.uiSelectOptions.onSelect) {
22418					this.uiSelectOptions.onSelect = function() {}
22419				}
22420				this.type = 'dateDropdowns';
22421
22422				Field.apply(this, arguments);
22423			}
22424
22425			DateDropdowns.prototype = Object.create(Field.prototype);
22426
22427			return new DateDropdowns(name, options);
22428		}
22429
22430		return dateDropdownsFactory;
22431	});
22432
22433},{"./Field":251}],251:[function(require,module,exports){
22434'use strict';
22435
22436function Field(name, config) {
22437	config = config || {};
22438
22439	this.name = name;
22440	this.form = null;
22441	this.validators = {};
22442	this.options = {};
22443	this.label = config.label || null;
22444	this.label_before = config.label_before || null;
22445	this.label_before_class = config.label_before_class || null;
22446
22447	if (config.validators) {
22448		this.addValidators(config.validators);
22449	}
22450
22451	if (config.options) {
22452		this.addOptions(config.options);
22453	}
22454
22455	if (config.fieldData) {
22456		angular.extend(this, config.fieldData);
22457	}
22458}
22459
22460Field.prototype.addValidators = function(validators) {
22461	this.validators = angular.merge(this.validators, validators);
22462
22463	return this;
22464};
22465Field.prototype.addValidator = function(name, options) {
22466	this.validators[name] = options;
22467
22468	return this;
22469};
22470Field.prototype.removeValidator = function(name) {
22471	delete this.validators[name];
22472
22473	return this;
22474};
22475
22476Field.prototype.addOptions = function(options) {
22477	this.options = angular.merge(this.options, options);
22478
22479	return this;
22480};
22481Field.prototype.addOption = function(name, options) {
22482	this.options[name] = options;
22483
22484	return this;
22485};
22486Field.prototype.removeOption = function(name) {
22487	delete this.options[name];
22488
22489	return this;
22490};
22491Field.prototype.link = function(element) {
22492	var $q = angular.injector(['ng']).get('$q');
22493
22494	return $q.when(element);
22495};
22496
22497Field.prototype.setForm = function(form) {
22498	this.form = form;
22499};
22500
22501
22502module.exports = Field;
22503
22504},{}],252:[function(require,module,exports){
22505'use strict';
22506
22507var Field = require('./Field');
22508
22509angular.module('dekky.forms.fields.fileUpload', ['angularFileUpload'])
22510.factory('FileUploadField', ["$log", "$q", "FileUploader", function($log, $q, FileUploader) {
22511	function fileUploadFactory(name, options) {
22512		function FileUpload(name, options) {
22513			this.type = 'fileUpload';
22514			this.uploader = new FileUploader(options.uploader);
22515
22516      if (!options.uploader.onWhenAddingFileFailed) {
22517        this.uploader.onWhenAddingFileFailed = function(item, filter) {
22518          var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
22519          showModalMessage(message);
22520        };
22521      }
22522      if (!options.uploader.onErrorItem) {
22523        this.uploader.onErrorItem = function() {
22524          showModalMessage('Невозможно загрузить файл на сервер');
22525        }
22526      }
22527
22528			Field.apply(this, arguments);
22529		}
22530
22531		FileUpload.prototype = Object.create(Field.prototype);
22532		FileUpload.prototype.link = function(template) {
22533			var input = angular.element(template[0].getElementsByTagName('input')[0]);
22534			var filters = angular.isDefined(input.attr('filters')) ?
22535				input.attr('filters') + ',' : '';
22536
22537			filters += this.uploader.filters.filter(function(filter) {
22538				return ['folder', 'queueLimit'].indexOf(filter.name) == -1;
22539			}).map(function(filter) {
22540				return filter.name;
22541			}).join(',');
22542
22543			if (angular.isDefined(this.uploader.queueLimit) && this.uploader.queueLimit > 0) {
22544				filters += ',queueLimit';
22545			}
22546
22547			input.attr('filters', filters);
22548
22549			if (this.multipleUpload) {
22550				input.attr('multiple', true);
22551			}
22552
22553			return $q.when(template);
22554		};
22555
22556		return new FileUpload(name, options);
22557	}
22558
22559	return fileUploadFactory;
22560}]);
22561
22562},{"./Field":251}],253:[function(require,module,exports){
22563'use strict';
22564
22565var Field = require('./Field');
22566
22567angular.module('dekky.forms.fields.hidden', [])
22568	.factory('HiddenField', function() {
22569		function hiddenFactory(name, options) {
22570			function Hidden(name, options) {
22571				this.type = 'hidden';
22572
22573				Field.apply(this, arguments);
22574			}
22575
22576			Hidden.prototype = Object.create(Field.prototype);
22577
22578			return new Hidden(name, options);
22579		}
22580
22581		return hiddenFactory;
22582	});
22583
22584},{"./Field":251}],254:[function(require,module,exports){
22585'use strict';
22586
22587var Field = require('./Field');
22588
22589angular.module('dekky.forms.fields.imageUpload', ['angularFileUpload'])
22590.factory('ImageUploadField', ["$log", "$q", "FileUploader", "fileUploadFilters", "showModalMessage", function($log, $q, FileUploader, fileUploadFilters, showModalMessage) {
22591	function fileUploadFactory(name, options) {
22592		var imageFilter = fileUploadFilters.fileType('png', 'jpg', 'jpeg', 'gif');
22593		var filesizeFilter = fileUploadFilters.fileSize();
22594
22595		function FileUpload(name, options) {
22596			this.type = 'imageUpload';
22597
22598			if (!options.uploader.personalUploader) {
22599				this.uploader = new FileUploader(options.uploader);
22600				this.uploader.filters = angular.merge(this.uploader.filters, [imageFilter, filesizeFilter], options.uploader.filters || []);
22601
22602				if (!options.uploader.onWhenAddingFileFailed) {
22603					this.uploader.onWhenAddingFileFailed = function(item, filter) {
22604						var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
22605						showModalMessage(message);
22606					};
22607				}
22608				if (!options.uploader.onErrorItem) {
22609					this.uploader.onErrorItem = function() {
22610						showModalMessage('Невозможно загрузить файл на сервер');
22611					}
22612				}
22613			} else {
22614				this.personalUplader = true;
22615				this.uploaderOptions = options.uploader;
22616			}
22617
22618			Field.apply(this, arguments);
22619		}
22620
22621		FileUpload.prototype = Object.create(Field.prototype);
22622		FileUpload.prototype.link = function(template, scope) {
22623			var uploader = this.uploader;
22624
22625			if (this.personalUplader) {
22626				scope.uploader = new FileUploader(this.uploaderOptions);
22627				scope.uploader.filters = angular.merge(scope.uploader.filters, [imageFilter, filesizeFilter], this.uploaderOptions.filters || []);
22628
22629				if (!this.uploaderOptions.onWhenAddingFileFailed) {
22630					scope.uploader.onWhenAddingFileFailed = function(item, filter) {
22631						var message = filter.message ? filter.message : 'Невозможно загрузить файл на сервер';
22632						showModalMessage(message);
22633					};
22634				}
22635				if (!this.uploaderOptions.onErrorItem) {
22636					scope.uploader.onErrorItem = function() {
22637						showModalMessage('Невозможно загрузить файл на сервер');
22638					}
22639				}
22640
22641				uploader = scope.uploader;
22642			}
22643
22644			var input = angular.element(template[0].getElementsByTagName('input')[0]);
22645			var filters = angular.isDefined(input.attr('filters')) ?
22646					input.attr('filters') + ',' : '';
22647
22648			filters += uploader.filters.filter(function(filter) {
22649				return ['folder', 'queueLimit'].indexOf(filter.name) == -1;
22650			}).map(function(filter) {
22651				return filter.name;
22652			}).join(',');
22653
22654			if (angular.isDefined(uploader.queueLimit) && uploader.queueLimit > 0) {
22655				filters += ',queueLimit';
22656			}
22657
22658			input.attr('filters', filters);
22659
22660			if (this.multipleUpload) {
22661				input.attr('multiple', true);
22662			}
22663
22664			return $q.when(template);
22665		};
22666
22667		return new FileUpload(name, options);
22668	}
22669
22670	return fileUploadFactory;
22671}]);
22672
22673},{"./Field":251}],255:[function(require,module,exports){
22674'use strict';
22675
22676var Field = require('./Field');
22677
22678angular.module('dekky.forms.fields.mountainAreaSelect', [])
22679.factory('MountainAreaSelectField', ["$timeout", "$rootScope", function($timeout, $rootScope) {
22680	function mountainAreaSelectFactory(name, options, items) {
22681		function MountainAreaSelect(name, options, items) {
22682			if (!Array.isArray(items)) {
22683				throw new Error('Not items for select');
22684			}
22685
22686			var that = this;
22687			this.type = 'mountainAreaSelect';
22688			this.items = items;
22689			this.selectedRegion = null;
22690			this.mountainAreas = [];
22691			this.model = null;
22692
22693			var modelWatch = $rootScope.$watch(function() {
22694				return that.model;
22695			}, function(newVal, oldVal) {
22696				if (newVal && !oldVal) {
22697					$timeout(function() {
22698						that.selectedRegion = newVal.mountain_region;
22699						var regionsWatch = $rootScope.$watch(function() {
22700							return that.items.length;
22701						}, function(newVal) {
22702							if (newVal > 0) {
22703								that.changeRegion();
22704								regionsWatch();
22705								modelWatch();
22706							}
22707						});
22708					});
22709				}
22710			});
22711
22712			Field.apply(this, arguments);
22713		}
22714
22715		MountainAreaSelect.prototype = Object.create(Field.prototype);
22716		MountainAreaSelect.prototype.changeRegion = function() {
22717			var that = this;
22718			$timeout(function() {
22719				if (that.selectedRegion) {
22720					that.items.forEach(function(region) {
22721						if (region.id == that.selectedRegion.id) {
22722							that.mountainAreas = region.mountain_areas;
22723						}
22724					})
22725				}
22726			});
22727		};
22728
22729		return new MountainAreaSelect(name, options, items);
22730	}
22731
22732	return mountainAreaSelectFactory;
22733}]);
22734
22735},{"./Field":251}],256:[function(require,module,exports){
22736'use strict';
22737
22738var Field = require('./Field');
22739
22740angular.module('dekky.forms.fields.mountainPeakSelect', [])
22741	.factory('MountainPeakSelectField', ["$log", "$q", "autocomplete", function($log, $q, autocomplete) {
22742		function mountainPeakSelectFactory(name, options) {
22743			function MountainPeakSelect(name, options) {
22744				options = options || {};
22745				this.type = 'mountainPeakSelect';
22746				this.items = autocomplete.get('mountainPeaks');
22747				this.uiSelectOptions = options.uiSelectOptions || {};
22748
22749				if (!this.uiSelectOptions.onSelect) {
22750					this.uiSelectOptions.onSelect = function() {}
22751				}
22752				if (!this.uiSelectOptions.refreshAutoComplete) {
22753					this.uiSelectOptions.refreshAutoComplete = autocomplete.refreshAutoComplete;
22754				}
22755
22756				Field.apply(this, arguments);
22757			}
22758
22759			MountainPeakSelect.prototype = Object.create(Field.prototype);
22760			MountainPeakSelect.prototype.link = function(template, scope) {
22761				var matchElement = template.find('ui-select-match'),
22762					choicesElement = template.find('ui-select-choices');
22763
22764				if (this.uiSelectOptions.matchTitle) {
22765					matchElement.text(this.uiSelectOptions.matchTitle);
22766				}
22767				if (this.uiSelectOptions.choicesTitle) {
22768					choicesElement.text(this.uiSelectOptions.choicesTitle);
22769				}
22770
22771				if (this.uiSelectOptions.multiple) {
22772					template.attr('multiple', '');
22773				}
22774
22775				if (angular.isDefined(this.uiSelectOptions.match)) {
22776					angular.forEach(this.uiSelectOptions.match, function(match, matchKey) {
22777						matchElement.attr(formsUtils.camelToDash(matchKey), match);
22778					});
22779				}
22780
22781				if (angular.isDefined(this.uiSelectOptions.choices)) {
22782					angular.forEach(this.uiSelectOptions.choices, function(choice, choiceKey) {
22783						choicesElement.attr(formsUtils.camelToDash(choiceKey), choice);
22784					});
22785				}
22786
22787				return $q.when(template);
22788			};
22789
22790			return new MountainPeakSelect(name, options);
22791		}
22792
22793		return mountainPeakSelectFactory;
22794	}]);
22795
22796},{"./Field":251}],257:[function(require,module,exports){
22797'use strict';
22798
22799var Field = require('./Field');
22800
22801angular.module('dekky.forms.fields.number', [])
22802	.factory('NumberField', function() {
22803		function numberFactory(name, options) {
22804			function Number(name, options) {
22805				this.type = 'number';
22806
22807				Field.apply(this, arguments);
22808			}
22809
22810			Number.prototype = Object.create(Field.prototype);
22811
22812			return new Number(name, options);
22813		}
22814
22815		return numberFactory;
22816	});
22817
22818},{"./Field":251}],258:[function(require,module,exports){
22819'use strict';
22820
22821var Field = require('./Field');
22822
22823require('../../services/utils.service');
22824
22825angular.module('dekky.forms.fields.radioCollection', ['dekky.forms.utils'])
22826	.factory('RadioCollectionField', ["$log", "$q", "formsUtils", function($log, $q, formsUtils) {
22827		function radioCollectionFactory(name, options, items) {
22828			function RadioCollection(name, options, items) {
22829				if (!Array.isArray(items)) {
22830					throw new Error('Not items for radio inputs');
22831				}
22832				if (angular.isUndefined(options.radio)) {
22833					throw new Error('Not options for radio input');
22834				}
22835				this.type = 'radioCollection';
22836				this.items = items;
22837				this.radio = options.radio;
22838				this.radioAttributes = options.radioAttributes || {};
22839
22840				Field.apply(this, arguments);
22841			}
22842
22843			RadioCollection.prototype = Object.create(Field.prototype);
22844			RadioCollection.prototype.link = function(template) {
22845				var radio = template.find('input');
22846
22847				angular.forEach(this.radioAttributes, function(value, attr) {
22848					if (angular.isFunction(value)) {
22849						radio.attr(formsUtils.camelToDash(attr), 'field.radioAttributes.' + attr + '()');
22850					} else {
22851						radio.attr(formsUtils.camelToDash(attr), value);
22852					}
22853				});
22854
22855				return $q.when(template);
22856			};
22857
22858			return new RadioCollection(name, options, items);
22859		}
22860
22861		return radioCollectionFactory;
22862	}]);
22863
22864},{"../../services/utils.service":276,"./Field":251}],259:[function(require,module,exports){
22865'use strict';
22866
22867var Field = require('./Field');
22868
22869angular.module('dekky.forms.fields.range', ['rzModule'])
22870	.factory('RangeField', function() {
22871		function rangeFactory(name, options) {
22872			function Range(name, options) {
22873				this.type = 'range';
22874				this.range = options.range;
22875
22876				Field.apply(this, arguments);
22877			}
22878
22879			Range.prototype = Object.create(Field.prototype);
22880
22881			return new Range(name, options);
22882		}
22883
22884		return rangeFactory;
22885	});
22886
22887},{"./Field":251}],260:[function(require,module,exports){
22888'use strict';
22889
22890var Field = require('./Field');
22891
22892angular.module('dekky.forms.fields.select', [])
22893.factory('SelectField', function() {
22894	function selectFactory(name, options, items) {
22895		function Select(name, options, items) {
22896			if (!Array.isArray(items)) {
22897				throw new Error('Not items for select');
22898			}
22899			if (options.selectOptions === undefined) {
22900				throw new Error('Not find select options');
22901			}
22902
22903			this.type = 'select';
22904			this.items = items;
22905			this.selectOptions = options.selectOptions;
22906
22907			Field.apply(this, arguments);
22908		}
22909
22910		Select.prototype = Object.create(Field.prototype);
22911
22912		return new Select(name, options, items);
22913	}
22914
22915	return selectFactory;
22916});
22917
22918},{"./Field":251}],261:[function(require,module,exports){
22919'use strict';
22920
22921var Field = require('./Field');
22922
22923angular.module('dekky.forms.fields.selectObject', [])
22924	.factory('SelectObjectField', function() {
22925		function selectObjectFactory(name, options, items) {
22926			function SelectObject(name, options, items) {
22927				if (!Array.isArray(items)) {
22928					throw new Error('Not items for select');
22929				}
22930				if (options.ngOptions === undefined) {
22931					throw new Error('Not defined ngOptions');
22932				}
22933
22934				this.name = name;
22935				this.type = 'selectObject';
22936				this.items = items;
22937				this.ngOptions = options.ngOptions;
22938
22939				Field.apply(this, arguments);
22940			}
22941
22942			SelectObject.prototype = Object.create(Field.prototype);
22943
22944			return new SelectObject(name, options, items);
22945		}
22946
22947		return selectObjectFactory;
22948	});
22949
22950},{"./Field":251}],262:[function(require,module,exports){
22951'use strict';
22952
22953var Field = require('./Field');
22954
22955angular.module('dekky.forms.fields.slider', ['rzModule'])
22956.factory('SliderField', function() {
22957	function sliderFactory(name, options) {
22958		function Slider(name, options) {
22959			this.type = 'slider';
22960			this.slider = options.slider;
22961
22962			Field.apply(this, arguments);
22963		}
22964
22965		Slider.prototype = Object.create(Field.prototype);
22966
22967		return new Slider(name, options);
22968	}
22969
22970	return sliderFactory;
22971});
22972
22973},{"./Field":251}],263:[function(require,module,exports){
22974'use strict';
22975
22976var Field = require('./Field');
22977
22978angular.module('dekky.forms.fields.text', [])
22979.factory('TextField', function() {
22980	function textFactory(name, options) {
22981		function Text(name, options) {
22982			this.type = 'text';
22983
22984			Field.apply(this, arguments);
22985		}
22986
22987		Text.prototype = Object.create(Field.prototype);
22988
22989		return new Text(name, options);
22990	}
22991
22992	return textFactory;
22993});
22994
22995},{"./Field":251}],264:[function(require,module,exports){
22996'use strict';
22997
22998var Field = require('./Field');
22999
23000angular.module('dekky.forms.fields.textarea', [])
23001	.factory('TextareaField', function() {
23002		function textareaFactory(name, options) {
23003			function Textarea(name, options) {
23004				this.type = 'textarea';
23005
23006				Field.apply(this, arguments);
23007			}
23008
23009			Textarea.prototype = Object.create(Field.prototype);
23010
23011			return new Textarea(name, options);
23012		}
23013
23014		return textareaFactory;
23015	});
23016
23017},{"./Field":251}],265:[function(require,module,exports){
23018'use strict';
23019
23020var Field = require('./Field');
23021
23022angular.module('dekky.forms.fields.uiDatepicker', ['ui.bootstrap'])
23023.factory('UiDatepickerField', ["$q", function($q) {
23024	function uiDatepickerFactory(name, options) {
23025		function UiDatepicker(name, options) {
23026			this.type = 'uiDatepicker';
23027			this.dateOptions = options.dateOptions;
23028			this.format = options.format;
23029
23030			Field.apply(this, arguments);
23031		}
23032
23033		UiDatepicker.prototype = Object.create(Field.prototype);
23034		UiDatepicker.prototype.link = function(template, scope) {
23035			scope.popup = {opened: false};
23036			scope.open = function() {
23037				scope.popup.opened = true;
23038			};
23039
23040			return $q.when(template);
23041		};
23042
23043		return new UiDatepicker(name, options);
23044	}
23045
23046	return uiDatepickerFactory;
23047}]);
23048
23049},{"./Field":251}],266:[function(require,module,exports){
23050'use strict';
23051
23052var Field = require('./Field');
23053
23054require('../../services/utils.service');
23055
23056angular.module('dekky.forms.fields.uiSelect', ['dekky.forms.utils', 'ui.select'])
23057	.factory('UiSelectField', ["$log", "$q", "formsUtils", function($log, $q, formsUtils) {
23058		function uiSelectFactory(name, options, items) {
23059			function UiSelect(name, options, items) {
23060				if (!Array.isArray(items)) {
23061					throw new Error('Not items for uiSelect');
23062				}
23063				if (options.uiSelectOptions === undefined) {
23064					throw new Error('Not find uiSelect options');
23065
23066				}
23067
23068				this.type = 'uiSelect';
23069				this.items = items;
23070				this.uiSelectOptions = options.uiSelectOptions;
23071
23072				Field.apply(this, arguments);
23073			}
23074
23075			UiSelect.prototype = Object.create(Field.prototype);
23076			UiSelect.prototype.link = function(template) {
23077				var matchElement = template.find('ui-select-match'),
23078					choicesElement = template.find('ui-select-choices');
23079				matchElement.text(this.uiSelectOptions.matchTitle);
23080				choicesElement.text(this.uiSelectOptions.choicesTitle);
23081
23082				if (this.uiSelectOptions.multiple) {
23083					template.attr('multiple', '');
23084				}
23085
23086				if (angular.isDefined(this.uiSelectOptions.match)) {
23087					angular.forEach(this.uiSelectOptions.match, function(match, matchKey) {
23088						matchElement.attr(formsUtils.camelToDash(matchKey), match);
23089					});
23090				}
23091
23092				if (angular.isDefined(this.uiSelectOptions.choices)) {
23093					angular.forEach(this.uiSelectOptions.choices, function(choice, choiceKey) {
23094						choicesElement.attr(formsUtils.camelToDash(choiceKey), choice);
23095					});
23096				}
23097
23098				return $q.when(template);
23099			};
23100
23101			return new UiSelect(name, options, items);
23102		}
23103
23104		return uiSelectFactory;
23105	}]);
23106
23107},{"../../services/utils.service":276,"./Field":251}],267:[function(require,module,exports){
23108'use strict';
23109
23110var Field = require('./Field');
23111
23112require('../../services/utils.service');
23113
23114angular.module('dekky.forms.fields.uiTypeahead', ['ui.bootstrap'])
23115	.factory('UiTypeaheadField', ["$q", function($q) {
23116		function uiTypeaheadFactory(name, options) {
23117			function UiTypeahead(name, options) {
23118				this.type = 'uiTypeahead';
23119				this.clearBtn = false;
23120
23121				Field.apply(this, arguments);
23122			}
23123
23124			UiTypeahead.prototype = Object.create(Field.prototype);
23125			UiTypeahead.prototype.link = function(template, scope) {
23126				scope.clear = function() {
23127					scope.model = undefined;
23128				};
23129
23130				return $q.when(template);
23131			};
23132
23133			return new UiTypeahead(name, options);
23134		}
23135
23136		return uiTypeaheadFactory;
23137	}]);
23138
23139},{"../../services/utils.service":276,"./Field":251}],268:[function(require,module,exports){
23140'use strict';
23141
23142var Field = require('./Field');
23143
23144angular.module('dekky.forms.fields.url', [])
23145.factory('UrlField', function() {
23146	function urlFactory(name, options) {
23147		function Url(name, options) {
23148			this.type = 'url';
23149
23150			Field.apply(this, arguments);
23151		}
23152
23153		Url.prototype = Object.create(Field.prototype);
23154
23155		return new Url(name, options);
23156	}
23157
23158	return urlFactory;
23159});
23160
23161},{"./Field":251}],269:[function(require,module,exports){
23162'use strict';
23163
23164var Field = require('./Field');
23165
23166angular.module('dekky.forms.fields.userSelect', [])
23167	.factory('UserSelectField', ["$log", "$q", "autocomplete", "formsUtils", function($log, $q, autocomplete, formsUtils) {
23168		function userSelectFactory(name, options, items) {
23169			function UserSelect(name, options, items) {
23170				options = options || {};
23171				this.type = 'userSelect';
23172				this.items = items;
23173				this.uiSelectOptions = options.uiSelectOptions || {};
23174
23175				if (!this.uiSelectOptions.onSelect) {
23176					this.uiSelectOptions.onSelect = function() {}
23177				}
23178				if (!this.uiSelectOptions.refreshAutoComplete) {
23179					this.uiSelectOptions.refreshAutoComplete = autocomplete.refreshAutoComplete;
23180				}
23181
23182				Field.apply(this, arguments);
23183			}
23184
23185			UserSelect.prototype = Object.create(Field.prototype);
23186			UserSelect.prototype.link = function(template, scope) {
23187				var matchElement = template.find('ui-select-match'),
23188					choicesElement = template.find('ui-select-choices');
23189
23190				if (this.uiSelectOptions.matchTitle) {
23191					matchElement.text(this.uiSelectOptions.matchTitle);
23192				}
23193				if (this.uiSelectOptions.choicesTitle) {
23194					choicesElement.text(this.uiSelectOptions.choicesTitle);
23195				}
23196
23197				if (this.uiSelectOptions.multiple) {
23198					template.attr('multiple', '');
23199				}
23200
23201				if (angular.isDefined(this.uiSelectOptions.match)) {
23202					angular.forEach(this.uiSelectOptions.match, function(match, matchKey) {
23203						matchElement.attr(formsUtils.camelToDash(matchKey), match);
23204					});
23205				}
23206
23207				if (angular.isDefined(this.uiSelectOptions.choices)) {
23208					angular.forEach(this.uiSelectOptions.choices, function(choice, choiceKey) {
23209						choicesElement.attr(formsUtils.camelToDash(choiceKey), choice);
23210					});
23211				}
23212
23213				return $q.when(template);
23214			};
23215
23216			return new UserSelect(name, options, items);
23217		}
23218
23219		return userSelectFactory;
23220	}]);
23221
23222},{"./Field":251}],270:[function(require,module,exports){
23223'use strict';
23224
23225angular.module('dekky.forms')
23226.provider('form', function() {
23227	this.defaults = {};
23228
23229	this.$get = ["$log", "formField", "formsConfig", function($log, formField, formsConfig) {
23230		function formFactory(name, config) {
23231			function Form(name) {
23232				this.name = name;
23233				this.config = angular.merge({}, formsConfig, config || {});
23234
23235				Object.defineProperty(this, '$fields', {
23236					value: {},
23237					enumerable: false
23238				});
23239			}
23240
23241			/**
23242			 * Добавляет новое поле в форму
23243			 *
23244			 * @param name
23245			 * @param type
23246			 * @param config
23247			 * @returns {formFactory}
23248			 */
23249			Form.prototype.addField = function(name, type, config, additionalParams) {
23250				type = type || 'text';
23251
23252				this.$fields[name] = formField(name, type, config, additionalParams);
23253				this.$fields[name].setForm(this);
23254
23255				return this;
23256			};
23257
23258			Form.prototype.field = function(name) {
23259				return this.$fields[name] || null;
23260			};
23261
23262			Form.prototype.setTheme = function(theme) {
23263				this.config.theme = theme;
23264			};
23265
23266			return new Form(name);
23267		}
23268
23269		return formFactory;
23270	}]
23271});
23272
23273},{}],271:[function(require,module,exports){
23274/**
23275 * Created by phatbass on 1/29/16.
23276 */
23277
23278angular.module('dekky.forms.autocomplete', [])
23279    .service('autocomplete', ["$http", "$q", function ($http, $q) {
23280        var objects = {};
23281        var self = this;
23282        var timeout = null;
23283
23284        this.check = function (object) {
23285            if (objects[object] === undefined) {
23286                objects[object] = [];
23287            }
23288        };
23289
23290        this.get = function (object) {
23291            self.check(object);
23292
23293            return objects[object];
23294        };
23295
23296        this.refreshAutoComplete = function (search, term, object, options) {
23297            if (object) {
23298                self.check(object);
23299
23300                objects[object].length = 0;
23301            }
23302
23303            if (!search) {
23304                if (object) {
23305                    return self.get(object);
23306                } else {
23307                    return $q.when([]);
23308                }
23309            }
23310
23311            var params = {
23312                term: term,
23313                search: search
23314            };
23315
23316            if (angular.isObject(options)) {
23317                params = angular.extend(params, options);
23318            }
23319
23320            return $http.post(Routing.generate('api_entities_post_autocomplete'), params)
23321                .then(function (response) {
23322                    if (object) {
23323                        objects[object].length = 0;
23324
23325                        response.data.forEach(function (route) {
23326                            objects[object].push(route);
23327                        });
23328                    } else {
23329                        return response.data;
23330                    }
23331                });
23332        }
23333    }]);
23334
23335},{}],272:[function(require,module,exports){
23336'use strict';
23337
23338angular.module('dekky.forms.fileUploadFilters', [])
23339.service('fileUploadFilters', function() {
23340	return {
23341		fileType: function() {
23342			var types = '';
23343
23344			if (arguments.length > 0) {
23345				for (var i = 0; i < arguments.length; i++) {
23346					types += arguments[i] + (i+1 < arguments.length ? '|' : '');
23347				}
23348			} else {
23349				types = 'jpg|jpeg|doc|docx|pdf|txt|xls|xlsx'; // Значения по-умолчанию
23350			}
23351
23352			var regex = new RegExp( '\.(' + types + ')$'),
23353				message = 'Разрешена загрузка только файлов следующих типов: ' +  types.split('|').join(', ');
23354
23355			return {
23356				name: 'fileType',
23357				message: message,
23358				fn: function(item) {
23359					return regex.test(item.name.toLowerCase());
23360				}
23361			}
23362		},
23363
23364		fileSize: function(size) {
23365			var sizeUnit = 'Мб.',
23366				sizeMessage;
23367			size = angular.isDefined(size) ? size : (25 * 1024 * 1024); // По-умолчанию 25 мб.
23368			sizeMessage = Math.floor(size / 1000000);
23369
23370			if (size < 1000000) {
23371				sizeUnit = 'Кб.';
23372				sizeMessage = Math.floor(size / 1000);
23373			}
23374
23375			return {
23376				name: 'fileSize',
23377				message: 'Разрешена загрузка файлов размером не больше ' + sizeMessage + ' ' + sizeUnit,
23378				fn: function(item) {
23379					return size ? item.size <= size : true;
23380				}
23381			}
23382		}
23383	}
23384});
23385
23386},{}],273:[function(require,module,exports){
23387/**
23388 * Created by phatbass on 1/29/16.
23389 */
23390
23391angular.module('dekky.forms.hideShowPassword', [])
23392	.service('hideShowPassword', function () {
23393		var inputType = 'password';
23394
23395		this.get = function () {
23396			return inputType;
23397		};
23398
23399		this.button = function () {
23400			if (inputType == 'password') {
23401				inputType = 'text';
23402			} else {
23403				inputType = 'password';
23404			}
23405		}
23406	});
23407
23408},{}],274:[function(require,module,exports){
23409/**
23410 * Created by phatbass on 1/1/16.
23411 */
23412
23413angular.module('dekky.forms.http', [])
23414    .service('http', ["$window", function ($window) {
23415        this.authenticationListener = function (response) {
23416            if (angular.isDefined(response.status) ) {
23417                if (response.status == 401) {
23418                    $window.location.href = Routing.generate('fos_user_security_login');
23419                }
23420            }
23421
23422            return response;
23423        }
23424    }]);
23425
23426},{}],275:[function(require,module,exports){
23427/**
23428 * Created by phatbass on 1/1/16.
23429 */
23430
23431angular.module('dekky.forms.softdeleteable', [])
23432	.service('softdeleteable', function () {
23433		var _progress = false,
23434			_objects = {},
23435			_model;
23436
23437		this.setModel = function (model) {
23438			_model = model;
23439		}
23440
23441		this.check = function (id) {
23442			if (_objects[id]) {
23443				return true;
23444			} else {
23445				return false;
23446			}
23447		}
23448
23449		this.delete = function (id, callback) {
23450			if (_progress == false) {
23451				_progress = true;
23452				_objects[id] = true;
23453
23454				_model.delete({id:id}, function() {
23455					_progress = false;
23456					if (callback) {
23457						callback();
23458					}
23459				});
23460			}
23461		}
23462
23463		this.restore = function (id) {
23464			if (_progress == false) {
23465				_objects[id] = false;
23466
23467				_model.restore({id:id});
23468			}
23469		}
23470	});
23471
23472},{}],276:[function(require,module,exports){
23473'use strict';
23474
23475angular.module('dekky.forms.utils', [])
23476	.service('formsUtils', function () {
23477		this.camelToDash = function (str) {
23478			return str.replace(/\W+/g, '-')
23479				.replace(/([a-z\d])([A-Z])/g, '$1-$2');
23480		};
23481
23482        /**
23483         * Функция возвращает окончание для множественного числа слова на основании числа и массива окончаний
23484         *
23485         * number Число на основе которого нужно сформировать окончание
23486         * array Массив слов или окончаний для чисел [1, 4, 5],
23487         *
23488         * например array['яблоко', 'яблока', 'яблок']
23489         */
23490		this.numEnding = function ( number, array ) {
23491            number = number % 100;
23492
23493            if (number >= 11 && number <= 19) {
23494                var ending = array[2];
23495            } else {
23496                var i = number % 10;
23497
23498                switch ( i ) {
23499                    case 1:
23500                        var ending = array[0];
23501                        break;
23502                    case 2:
23503                    case 3:
23504                    case 4:
23505                        var ending = array[1];
23506                        break;
23507                    default:
23508                        var ending = array[2];
23509                        break;
23510                }
23511            }
23512
23513            return ending;
23514		}
23515	});
23516
23517},{}],277:[function(require,module,exports){
23518'use strict';
23519
23520angular.module('dekky.forms.themes.bootstrap', []);
23521
23522},{}],278:[function(require,module,exports){
23523require('./bootstrap-theme');
23524
23525require('./row');
23526
23527require('./fields/checkbox');
23528require('./fields/checkboxCollection');
23529require('./fields/collection');
23530require('./fields/dateDropdowns');
23531require('./fields/fileUpload');
23532require('./fields/imageUpload');
23533require('./fields/mountainAreaSelect');
23534require('./fields/mountainPeakSelect');
23535require('./fields/userSelect');
23536require('./fields/hidden');
23537require('./fields/number');
23538require('./fields/range');
23539require('./fields/radioCollection');
23540require('./fields/select');
23541require('./fields/selectObject');
23542require('./fields/slider');
23543require('./fields/text');
23544require('./fields/textarea');
23545require('./fields/uiSelect');
23546require('./fields/uiDatepicker');
23547require('./fields/uiTypeahead');
23548require('./fields/url');
23549
23550},{"./bootstrap-theme":277,"./fields/checkbox":279,"./fields/checkboxCollection":280,"./fields/collection":281,"./fields/dateDropdowns":282,"./fields/fileUpload":283,"./fields/hidden":284,"./fields/imageUpload":285,"./fields/mountainAreaSelect":286,"./fields/mountainPeakSelect":287,"./fields/number":288,"./fields/radioCollection":289,"./fields/range":290,"./fields/select":291,"./fields/selectObject":292,"./fields/slider":293,"./fields/text":294,"./fields/textarea":295,"./fields/uiDatepicker":296,"./fields/uiSelect":297,"./fields/uiTypeahead":298,"./fields/url":299,"./fields/userSelect":300,"./row":301}],279:[function(require,module,exports){
23551'use strict';
23552
23553angular.module('dekky.forms.themes.bootstrap')
23554.run(["$templateCache", function($templateCache) {
23555	$templateCache.put('/dekky.forms/themes/bootstrap/fields/checkbox.html',
23556		'<input type="checkbox" ng-model="model" name="{{ field.name }}" id="{{ field.name }}">'+
23557        ' <label for="{{ field.name }}" ng-if="field.label">{{ field.label }}</label>'
23558	);
23559}]);
23560
23561},{}],280:[function(require,module,exports){
23562'use strict';
23563
23564angular.module('dekky.forms.themes.bootstrap')
23565	.run(["$templateCache", function($templateCache) {
23566		$templateCache.put('/dekky.forms/themes/bootstrap/fields/checkboxCollection.html',
23567			'<div class="form-group">' +
23568                '<div class="checkbox" ng-repeat="item in field.items">' +
23569                    '<label>' +
23570                        '<input ng-disabled="item.disabled" name="{{ field.name + \'_\' + $index }}" type="checkbox" ng-model="item[field.checkbox.model]" id="{{ field.name + \'_\' + $index }}"> {{ item[field.checkbox.label] }}' +
23571                    '</label>' +
23572                '</div>' +
23573			'</div>'
23574		);
23575	}]);
23576
23577},{}],281:[function(require,module,exports){
23578'use strict';
23579
23580angular.module('dekky.forms.themes.bootstrap')
23581.run(["$templateCache", function($templateCache) {
23582	$templateCache.put('/dekky.forms/themes/bootstrap/fields/collection.html',
23583		'<div ng-init="model = model || []" ng-model="model">' +
23584			'<div repeat-collection class="panel panel-default">' +
23585				'<div class="panel-body">' +
23586					'<form-row ng-repeat="(key, itemField) in field.childForm.$fields" ng-model="item[key]" field="itemField"></form-row>' +
23587					'<div class="row">' +
23588						'<div class="col-sm-12 text-right">' +
23589							'<p><button class="btn btn-danger btn-sm" type="button" ng-click="field.doDelete(item, model, $index)"><i class="fa fa-trash-o"></i> {{ field.buttons.remove }}</button></p>' +
23590						'</div>' +
23591					'</div>' +
23592				'</div>' +
23593			'</div>' +
23594
23595			'<div class="row">' +
23596				'<div class="col-sm-12">' +
23597					'<p><button class="btn btn-default btn-sm btn-success" type="button" ng-click="field.addItem(model)"><i class="fa fa-plus"></i> {{ field.buttons.add }}</button></p>' +
23598				'</div>' +
23599			'</div>' +
23600		'</div>'
23601	);
23602}]);
23603
23604},{}],282:[function(require,module,exports){
23605'use strict';
23606
23607angular.module('dekky.forms.themes.bootstrap')
23608.run(["$templateCache", function($templateCache) {
23609	$templateCache.put('/dekky.forms/themes/bootstrap/fields/dateDropdowns.html',
23610		'<input rsmdatedropdowns ng-model="model" name="{{ field.name }}" id="{{ field.name }}">'
23611	);
23612}]);
23613
23614},{}],283:[function(require,module,exports){
23615'use strict';
23616
23617angular.module('dekky.forms.themes.bootstrap')
23618.run(["$templateCache", function($templateCache) {
23619	$templateCache.put('/dekky.forms/themes/bootstrap/fields/fileUpload.html',
23620		'<div class="row" ng-init="model = field.uploader.queue">' +
23621			'<div class="col-sm-12">' +
23622				'<input class="df-uploader__file-input" id="{{ field.name }}" type="file" nv-file-select uploader="field.uploader">' +
23623			'</div>',
23624		'</div>'
23625	);
23626}]);
23627
23628},{}],284:[function(require,module,exports){
23629'use strict';
23630
23631angular.module('dekky.forms.themes.bootstrap')
23632	.run(["$templateCache", function($templateCache) {
23633		$templateCache.put('/dekky.forms/themes/bootstrap/fields/hidden.html',
23634			'<input type="hidden" value="{{ model }}" name="{{ field.name }}" id="{{ field.name }}">'
23635		);
23636	}]);
23637
23638},{}],285:[function(require,module,exports){
23639'use strict';
23640
23641angular.module('dekky.forms.themes.bootstrap')
23642.run(["$templateCache", function($templateCache) {
23643	$templateCache.put('/dekky.forms/themes/bootstrap/fields/imageUpload.html',
23644		'<div class="row" ng-init="model = field.uploader.queue">' +
23645			'<div class="col-sm-12">' +
23646				'<input class="df-uploader__file-input" id="{{ field.name }}" type="file" nv-file-select uploader="field.uploader">' +
23647			'</div>',
23648		'</div>'
23649	);
23650}]);
23651
23652},{}],286:[function(require,module,exports){
23653'use strict';
23654
23655angular.module('dekky.forms.themes.bootstrap')
23656.run(["$templateCache", function($templateCache) {
23657	$templateCache.put('/dekky.forms/themes/bootstrap/fields/mountainAreaSelect.html',
23658		'<label for="{{ field.name + \'_region\' }}" ng-if="field.labelRegion">{{ field.labelRegion }}</label>' +
23659		'<select class="form-control" ng-model="field.selectedRegion" name="{{ field.name + \'_region\' }}" id="{{ field.name + \'_region\' }}" ng-options="item as item.name for item in field.items track by item.id" ng-change="field.changeRegion()"></select>' +
23660		'<label for="{{ field.name + \'_area\' }}" ng-if="field.labelArea">{{ field.labelArea }}</label>' +
23661		'<select class="form-control" ng-model="model" name="{{ field.name + \'_area\' }}" id="{{ field.name + \'_area\' }}" ng-options="item as item.name for item in field.mountainAreas track by item.id"></select>'
23662	);
23663}]);
23664
23665},{}],287:[function(require,module,exports){
23666'use strict';
23667
23668angular.module('dekky.forms.themes.bootstrap')
23669.run(["$templateCache", function($templateCache) {
23670	$templateCache.put('/dekky.forms/themes/bootstrap/fields/mountainPeakSelect.html',
23671		'<ui-select ng-model="model" id="{{ field.name }}" name="{{ field.name }}" on-select="field.uiSelectOptions.onSelect($item, $model, $select.ngModel.$options)">' +
23672			'<ui-select-match class="ui-select-match" placeholder="Введите вершину..."><span ng-bind="$select.selected.name"></span></ui-select-match>' +
23673			'<ui-select-choices ' +
23674				'class="ui-select-choices"' +
23675				'repeat="item in field.items track by item.id"' +
23676				'refresh="field.uiSelectOptions.refreshAutoComplete($select.search, \'MountainPeak\', \'mountainPeaks\')"' +
23677				'refresh-delay="0"' +
23678				'><span ng-bind="item.name"></span><span ng-bind="item.region_name"></span><span ng-bind="item.area_name"></span></ui-select-choices>' +
23679		'</ui-select>'
23680	);
23681}]);
23682
23683},{}],288:[function(require,module,exports){
23684'use strict';
23685
23686angular.module('dekky.forms.themes.bootstrap')
23687	.run(["$templateCache", function($templateCache) {
23688		$templateCache.put('/dekky.forms/themes/bootstrap/fields/number.html',
23689			'<input type="number" class="form-control" ng-model="model" name="{{ field.name }}" id="{{ field.name }}">'
23690		);
23691	}]);
23692
23693},{}],289:[function(require,module,exports){
23694'use strict';
23695
23696angular.module('dekky.forms.themes.bootstrap')
23697	.run(["$templateCache", function($templateCache) {
23698		$templateCache.put('/dekky.forms/themes/bootstrap/fields/radioCollection.html',
23699			'<div class="form-group" ng-repeat="item in field.items">' +
23700				'<label class="form__radio">' +
23701					'<input class="form__radio" name="{{ field.name }}" type="radio" ng-model="model" ng-value="item" id="{{ field.name + \'_\' + $index }}">' +
23702					'<span class="form__radio_text">{{ item[field.radio.label] }}</span>' +
23703				'</label>' +
23704			'</div>'
23705		);
23706	}]);
23707
23708},{}],290:[function(require,module,exports){
23709'use strict';
23710
23711angular.module('dekky.forms.themes.bootstrap')
23712.run(["$templateCache", function($templateCache) {
23713	$templateCache.put('/dekky.forms/themes/bootstrap/fields/range.html',
23714		'<rzslider rz-slider-model="model.min" rz-slider-high="model.max" rz-slider-options="field.range"></rzslider>'
23715	);
23716}]);
23717
23718},{}],291:[function(require,module,exports){
23719'use strict';
23720
23721angular.module('dekky.forms.themes.bootstrap')
23722.run(["$templateCache", function($templateCache) {
23723	$templateCache.put('/dekky.forms/themes/bootstrap/fields/select.html',
23724		'<select class="form-control" ng-model="model" name="{{ field.name }}" id="{{ field.name }}">' +
23725			'<option ng-repeat="item in field.items" value="{{ item[field.selectOptions.value] }}">{{ item[field.selectOptions.label] }}</option>' +
23726		'</select>'
23727	);
23728}]);
23729
23730},{}],292:[function(require,module,exports){
23731'use strict';
23732
23733angular.module('dekky.forms.themes.bootstrap')
23734	.run(["$templateCache", function($templateCache) {
23735		$templateCache.put('/dekky.forms/themes/bootstrap/fields/selectObject.html',
23736			'<select class="form-control" ng-model="model" name="{{ field.name }}" id="{{ field.name }}" ng-options="{{ field.ngOptions }}"></select>'
23737		);
23738	}]);
23739
23740},{}],293:[function(require,module,exports){
23741'use strict';
23742
23743angular.module('dekky.forms.themes.bootstrap')
23744.run(["$templateCache", function($templateCache) {
23745	$templateCache.put('/dekky.forms/themes/bootstrap/fields/slider.html',
23746		'<rzslider rz-slider-model="model" rz-slider-options="field.slider"></rzslider>'
23747	);
23748}]);
23749
23750},{}],294:[function(require,module,exports){
23751'use strict';
23752
23753angular.module('dekky.forms.themes.bootstrap')
23754.run(["$templateCache", function($templateCache) {
23755	$templateCache.put('/dekky.forms/themes/bootstrap/fields/text.html',
23756		'<input type="text" class="form-control" ng-model="model" name="{{ field.name }}" id="{{ field.name }}">'
23757	);
23758}]);
23759
23760},{}],295:[function(require,module,exports){
23761'use strict';
23762
23763angular.module('dekky.forms.themes.bootstrap')
23764	.run(["$templateCache", function($templateCache) {
23765		$templateCache.put('/dekky.forms/themes/bootstrap/fields/textarea.html',
23766			'<textarea class="form-control" ng-model="model" name="{{ field.name }}" id="{{ field.name }}"></textarea>'
23767		);
23768	}]);
23769
23770},{}],296:[function(require,module,exports){
23771'use strict';
23772
23773angular.module('dekky.forms.themes.bootstrap')
23774	.run(["$templateCache", function ($templateCache) {
23775		$templateCache.put('/dekky.forms/themes/bootstrap/fields/uiDatepicker.html',
23776			'<p class="input-group">' +
23777				'<input type="text" class="form-control" name="{{ field.name }}" id="{{ field.name }}" ng-model="model" uib-datepicker-popup="{{ field.format }}" is-open="popup.opened" datepicker-options="field.dateOptions" close-text="Close" />' +
23778				'<span class="input-group-btn">' +
23779					'<button type="button" class="btn btn-default" ng-click="open()"><i class="glyphicon glyphicon-calendar"></i></button>' +
23780				'</span>' +
23781			'</p>'
23782		);
23783	}]);
23784
23785},{}],297:[function(require,module,exports){
23786'use strict';
23787
23788angular.module('dekky.forms.themes.bootstrap')
23789	.run(["$templateCache", function($templateCache) {
23790		$templateCache.put('/dekky.forms/themes/bootstrap/fields/uiSelect.html',
23791			'<ui-select ng-model="model" id="{{ field.name }}" name="{{ field.name }}">' +
23792				'<ui-select-match class="ui-select-match"></ui-select-match>' +
23793				'<ui-select-choices class="ui-select-choices"></ui-select-choices>' +
23794			'</ui-select>'
23795		);
23796	}]);
23797
23798},{}],298:[function(require,module,exports){
23799'use strict';
23800
23801angular.module('dekky.forms.themes.bootstrap')
23802	.run(["$templateCache", function($templateCache) {
23803		$templateCache.put('/dekky.forms/themes/bootstrap/fields/uiTypeahead.html',
23804			'<input type="text" ng-model="model" name="{{ field.name }}" id="{{ field.name }}" class="form-control">' +
23805			'<button class="btn-clear" ng-if="field.clearBtn" type="button" ng-click="clear()"></button>'
23806		);
23807	}]);
23808
23809},{}],299:[function(require,module,exports){
23810'use strict';
23811
23812angular.module('dekky.forms.themes.bootstrap')
23813.run(["$templateCache", function($templateCache) {
23814	$templateCache.put('/dekky.forms/themes/bootstrap/fields/url.html',
23815		'<input type="url" class="form-control" ng-model="model" name="{{ field.name }}" id="{{ field.name }}">'
23816	);
23817}]);
23818
23819},{}],300:[function(require,module,exports){
23820'use strict';
23821
23822angular.module('dekky.forms.themes.bootstrap')
23823.run(["$templateCache", function($templateCache) {
23824	$templateCache.put('/dekky.forms/themes/bootstrap/fields/userSelect.html',
23825		'<ui-select ng-model="model" id="{{ field.name }}" name="{{ field.name }}" on-select="field.uiSelectOptions.onSelect($item, $model, $select.ngModel.$options)">' +
23826			'<ui-select-match class="ui-select-match" placeholder="Введите вершину..."><span ng-bind="$select.selected.fio"></span></ui-select-match>' +
23827			'<ui-select-choices ' +
23828				'class="ui-select-choices"' +
23829				'repeat="item in field.items track by item.id"' +
23830				'refresh="field.uiSelectOptions.refreshAutoComplete($select.search, \'Users\', \'users\')"' +
23831				'refresh-delay="0"' +
23832			'><span ng-bind="item.fio"></span><span ng-if="item.p0" ng-bind="item.p0"></span><span ng-if="item.p1" ng-bind="item.p1"></span></ui-select-choices>' +
23833		'</ui-select>'
23834	);
23835}]);
23836
23837},{}],301:[function(require,module,exports){
23838'use strict';
23839
23840angular.module('dekky.forms.themes.bootstrap')
23841.run(["$templateCache", function($templateCache) {
23842	$templateCache.put('/dekky.forms/themes/bootstrap/row.html',
23843		'<div class="form-group inline">' +
23844			'<label for="{{ field.name }}" ng-if="field.label && field.type != \'checkbox\'">{{ field.label }}</label>' +
23845			'<form-widget field="field" ng-model="model"></form-widget>' +
23846		'</div>'
23847	);
23848}]);
23849
23850},{}],302:[function(require,module,exports){
23851'use strict';
23852
23853angular.module('dekky.forms.themes.far', []);
23854
23855},{}],303:[function(require,module,exports){
23856require('./far-theme');
23857
23858require('./row');
23859
23860require('./fields/checkbox');
23861require('./fields/checkboxCollection');
23862require('./fields/collection');
23863require('./fields/dateDropdowns');
23864require('./fields/fileUpload');
23865require('./fields/imageUpload');
23866require('./fields/mountainPeakSelect');
23867require('./fields/userSelect');
23868require('./fields/hidden');
23869require('./fields/number');
23870require('./fields/range');
23871require('./fields/radioCollection');
23872require('./fields/select');
23873require('./fields/selectObject');
23874require('./fields/slider');
23875require('./fields/text');
23876require('./fields/textRepeat');
23877require('./fields/textarea');
23878require('./fields/uiSelect');
23879require('./fields/uiDatepicker');
23880require('./fields/uiTypeahead');
23881require('./fields/url');
23882
23883},{"./far-theme":302,"./fields/checkbox":304,"./fields/checkboxCollection":305,"./fields/collection":306,"./fields/dateDropdowns":307,"./fields/fileUpload":308,"./fields/hidden":309,"./fields/imageUpload":310,"./fields/mountainPeakSelect":311,"./fields/number":312,"./fields/radioCollection":313,"./fields/range":314,"./fields/select":315,"./fields/selectObject":316,"./fields/slider":317,"./fields/text":318,"./fields/textRepeat":319,"./fields/textarea":320,"./fields/uiDatepicker":321,"./fields/uiSelect":322,"./fields/uiTypeahead":323,"./fields/url":324,"./fields/userSelect":325,"./row":326}],304:[function(require,module,exports){
23884'use strict';
23885
23886angular.module('dekky.forms.themes.far')
23887.run(["$templateCache", function($templateCache) {
23888	$templateCache.put('/dekky.forms/themes/far/fields/checkbox.html',
23889			'<label class="form__checkbox">' +
23890			'<input class="form__checkbox_hidden" type="checkbox" ng-model="model" ng-disabled="field.disabled" name="{{ field.name }}" id="{{ field.name }}">' +
23891			'<span class="form__checkbox_indicator"></span>' +
23892			'<span class="form__checkbox_text">{{ field.label }}</span>' +
23893		'</label>'
23894	);
23895}]);
23896
23897},{}],305:[function(require,module,exports){
23898'use strict';
23899
23900angular.module('dekky.forms.themes.far')
23901	.run(["$templateCache", function($templateCache) {
23902		$templateCache.put('/dekky.forms/themes/far/fields/checkboxCollection.html',
23903			'<div class="form-group" ng-repeat="item in field.items">' +
23904				'<label class="form__checkbox">' +
23905					'<input class="form__checkbox_hidden group-required" ng-disabled="item.disabled" name="{{ field.name + \'_\' + $index }}" type="checkbox" ng-model="item[field.checkbox.model]" id="{{ field.name + \'_\' + $index }}">' +
23906					'<span class="form__checkbox_indicator"></span>' +
23907					'<span class="form__checkbox_text">{{ item[field.checkbox.label] }}</span>' +
23908				'</label>' +
23909			'</div>'
23910		);
23911	}]);
23912
23913},{}],306:[function(require,module,exports){
23914'use strict';
23915
23916angular.module('dekky.forms.themes.far')
23917.run(["$templateCache", function($templateCache) {
23918	$templateCache.put('/dekky.forms/themes/far/fields/collection.html',
23919		'<div ng-init="model = model || []" ng-model="model">' +
23920			'<div repeat-collection class="panel panel-default">' +
23921				'<div class="panel-body">' +
23922					'<form-row ng-repeat="(key, itemField) in field.childForm.$fields" ng-model-options="{ index: $index }" ng-model="item[key]" field="itemField"></form-row>' +
23923					'<div class="row">' +
23924						'<div class="col-sm-12 text-right">' +
23925							'<p><button class="btn btn-danger btn-sm" type="button" ng-click="field.doDelete(item, model, $index)">
23925<i class="fa fa-trash-o"></i> {{ field.buttons.remove }}</button></p>' +
23926						'</div>' +
23927					'</div>' +
23928				'</div>' +
23929			'</div>' +
23930
23931			'<div class="row">' +
23932				'<div class="col-sm-12">' +
23933					'<p><button class="btn btn-default btn-sm btn-success" type="button" ng-click="field.addItem(model)"><i class="fa fa-plus"></i> {{ field.buttons.add }}</button></p>' +
23934				'</div>' +
23935			'</div>' +
23936		'</div>'
23937	);
23938}]);
23939
23940},{}],307:[function(require,module,exports){
23941'use strict';
23942
23943angular.module('dekky.forms.themes.bootstrap')
23944.run(["$templateCache", function($templateCache) {
23945	$templateCache.put('/dekky.forms/themes/far/fields/dateDropdowns.html',
23946		'<input rsmdatedropdowns ng-model="model" name="{{ field.name }}" id="{{ field.name }}">'
23947	);
23948}]);
23949
23950},{}],308:[function(require,module,exports){
23951'use strict';
23952
23953angular.module('dekky.forms.themes.far')
23954.run(["$templateCache", function($templateCache) {
23955	$templateCache.put('/dekky.forms/themes/far/fields/fileUpload.html',
23956		'<div ng-init="model = field.uploader.queue">' +
23957			'<input class="btn-file-upload__input" id="{{ field.name }}" type="file" nv-file-select uploader="field.uploader">' +
23958		'</div>'
23959	);
23960}]);
23961
23962},{}],309:[function(require,module,exports){
23963'use strict';
23964
23965angular.module('dekky.forms.themes.far')
23966	.run(["$templateCache", function($templateCache) {
23967		$templateCache.put('/dekky.forms/themes/far/fields/hidden.html',
23968			'<input type="hidden" value="{{ model }}" name="{{ field.name }}" id="{{ field.name }}">'
23969		);
23970	}]);
23971
23972},{}],310:[function(require,module,exports){
23973'use strict';
23974
23975angular.module('dekky.forms.themes.far')
23976.run(["$templateCache", function($templateCache) {
23977	$templateCache.put('/dekky.forms/themes/far/fields/imageUpload.html',
23978		'<span ng-init="model = field.uploader.queue">' +
23979			'<input class="btn-file-upload__input" id="{{ field.name }}" type="file" nv-file-select uploader="field.uploader">' +
23980		'</span>'
23981	);
23982}]);
23983
23984},{}],311:[function(require,module,exports){
23985'use strict';
23986
23987angular.module('dekky.forms.themes.far')
23988	.run(["$templateCache", function($templateCache) {
23989		$templateCache.put('/dekky.forms/themes/far/fields/mountainPeakSelect.html',
23990			'<ui-select class="form__ui-select" ng-model="model" id="{{ field.name }}" name="{{ field.name }}" on-select="field.uiSelectOptions.onSelect($item, $model, $select.ngModel.$options)">' +
23991				'<ui-select-match class="ui-select-match" placeholder="Введите вершину..."><span ng-bind="$select.selected.name"></span></ui-select-match>' +
23992				'<ui-select-choices ' +
23993					'class="ui-select-choices"' +
23994					'repeat="item in field.items track by item.id"' +
23995					'refresh="field.uiSelectOptions.refreshAutoComplete($select.search, \'MountainPeak\', \'mountainPeaks\')"' +
23996					'refresh-delay="0"' +
23997				'><span ng-bind="item.name"></span><span ng-bind="item.region_name"></span><span ng-bind="item.area_name"></span></ui-select-choices>' +
23998			'</ui-select>'
23999		);
24000	}]);
24001
24002},{}],312:[function(require,module,exports){
24003'use strict';
24004
24005angular.module('dekky.forms.themes.far')
24006	.run(["$templateCache", function($templateCache) {
24007		$templateCache.put('/dekky.forms/themes/far/fields/number.html',
24008			'<input type="number" class="form-control" ng-model="model" name="{{ field.name }}" id="{{ field.name }}">'
24009		);
24010	}]);
24011
24012},{}],313:[function(require,module,exports){
24013'use strict';
24014
24015angular.module('dekky.forms.themes.far')
24016	.run(["$templateCache", function($templateCache) {
24017		$templateCache.put('/dekky.forms/themes/far/fields/radioCollection.html',
24018			'<div class="form-group" ng-repeat="item in field.items">' +
24019				'<label class="form__radio">' +
24020					'<input class="form__radio_hidden" name="{{ field.name }}" type="radio" ng-model="model" ng-value="item" id="{{ field.name + \'_\' + $index }}">' +
24021					'<span class="form__radio_indicator"></span>' +
24022					'<span class="form__radio_text">{{ item[field.radio.label] }}</span>' +
24023				'</label>' +
24024			'</div>'
24025		);
24026	}]);
24027
24028},{}],314:[function(require,module,exports){
24029'use strict';
24030
24031angular.module('dekky.forms.themes.far')
24032.run(["$templateCache", function($templateCache) {
24033	$templateCache.put('/dekky.forms/themes/far/fields/range.html',
24034		'<rzslider rz-slider-model="model.min" rz-slider-high="model.max" rz-slider-options="field.range"></rzslider>'
24035	);
24036}]);
24037
24038},{}],315:[function(require,module,exports){
24039'use strict';
24040
24041angular.module('dekky.forms.themes.far')
24042.run(["$templateCache", function($templateCache) {
24043	$templateCache.put('/dekky.forms/themes/far/fields/select.html',
24044		'<select class="form-control" ng-model="model" name="{{ field.name }}" id="{{ field.name }}">' +
24045			'<option ng-repeat="item in field.items" value="{{ item[field.selectOptions.value] }}">{{ item[field.selectOptions.label] }}</option>' +
24046		'</select>'
24047	);
24048}]);
24049
24050},{}],316:[function(require,module,exports){
24051'use strict';
24052
24053angular.module('dekky.forms.themes.far')
24054	.run(["$templateCache", function($templateCache) {
24055		$templateCache.put('/dekky.forms/themes/far/fields/selectObject.html',
24056			'<select class="form-control" ng-model="model" name="{{ field.name }}" id="{{ field.name }}" ng-options="{{ field.ngOptions }}"></select>'
24057		);
24058	}]);
24059
24060},{}],317:[function(require,module,exports){
24061'use strict';
24062
24063angular.module('dekky.forms.themes.far')
24064.run(["$templateCache", function($templateCache) {
24065	$templateCache.put('/dekky.forms/themes/far/fields/slider.html',
24066		'<rzslider rz-slider-model="model" rz-slider-options="field.slider"></rzslider>'
24067	);
24068}]);
24069
24070},{}],318:[function(require,module,exports){
24071'use strict';
24072
24073angular.module('dekky.forms.themes.far')
24074.run(["$templateCache", function($templateCache) {
24075	$templateCache.put('/dekky.forms/themes/far/fields/text.html',
24076		'<input type="text" class="form__item" ng-model="model" name="{{ field.name }}" id="{{ field.name }}">{{index}}'
24077	);
24078}]);
24079
24080},{}],319:[function(require,module,exports){
24081'use strict';
24082
24083angular.module('dekky.forms.themes.far')
24084.run(["$templateCache", function($templateCache) {
24085	$templateCache.put('/dekky.forms/themes/far/fields/textRepeat.html',
24086		'<input type="text" class="form__item" ng-model="model" name="{{ field.name + $index }}" id="{{ field.name }}">{{field.name}}'
24087	);
24088}]);
24089
24090},{}],320:[function(require,module,exports){
24091'use strict';
24092
24093angular.module('dekky.forms.themes.far')
24094	.run(["$templateCache", function($templateCache) {
24095		$templateCache.put('/dekky.forms/themes/far/fields/textarea.html',
24096			'<textarea class="form-control" ng-model="model" name="{{ field.name }}" id="{{ field.name }}"></textarea>'
24097		);
24098	}]);
24099
24100},{}],321:[function(require,module,exports){
24101'use strict';
24102
24103angular.module('dekky.forms.themes.far')
24104	.run(["$templateCache", function ($templateCache) {
24105		$templateCache.put('/dekky.forms/themes/far/fields/uiDatepicker.html',
24106			'<p class="input-group">' +
24107				'<input type="text" class="form-control" name="{{ field.name }}" id="{{ field.name }}" ng-model="model" uib-datepicker-popup="{{ field.format }}" is-open="popup.opened" datepicker-options="field.dateOptions" close-text="Close" />' +
24108				'<span class="input-group-btn">' +
24109					'<button type="button" class="btn btn-default" ng-click="open()"><i class="glyphicon glyphicon-calendar"></i></button>' +
24110				'</span>' +
24111			'</p>'
24112		);
24113	}]);
24114
24115},{}],322:[function(require,module,exports){
24116'use strict';
24117
24118angular.module('dekky.forms.themes.far')
24119	.run(["$templateCache", function($templateCache) {
24120		$templateCache.put('/dekky.forms/themes/far/fields/uiSelect.html',
24121			'<ui-select ng-model="model" id="{{ field.name }}" name="{{ field.name }}" ng-disabled="disabled">' +
24122				'<ui-select-match class="ui-select-match"></ui-select-match>' +
24123				'<ui-select-choices class="ui-select-choices"></ui-select-choices>' +
24124			'</ui-select>'
24125		);
24126	}]);
24127
24128},{}],323:[function(require,module,exports){
24129'use strict';
24130
24131angular.module('dekky.forms.themes.far')
24132	.run(["$templateCache", function($templateCache) {
24133		$templateCache.put('/dekky.forms/themes/far/fields/uiTypeahead.html',
24134			'<input type="text" ng-model="model" name="{{ field.name }}" id="{{ field.name }}">' +
24135			'<button class="btn-clear" ng-if="field.clearBtn" type="button" ng-click="clear()"></button>'
24136		);
24137	}]);
24138
24139},{}],324:[function(require,module,exports){
24140'use strict';
24141
24142angular.module('dekky.forms.themes.far')
24143.run(["$templateCache", function($templateCache) {
24144	$templateCache.put('/dekky.forms/themes/far/fields/url.html',
24145		'<input type="url" class="form__item" ng-model="model" name="{{ field.name }}" id="{{ field.name }}">{{index}}'
24146	);
24147}]);
24148
24149},{}],325:[function(require,module,exports){
24150'use strict';
24151
24152angular.module('dekky.forms.themes.far')
24153	.run(["$templateCache", function($templateCache) {
24154		$templateCache.put('/dekky.forms/themes/far/fields/userSelect.html',
24155			'<ui-select class="form__ui-select" ng-model="model" id="{{ field.name }}" name="{{ field.name }}" on-select="field.uiSelectOptions.onSelect($item, $model, $select.ngModel.$options)">' +
24156				'<ui-select-match class="ui-select-match" placeholder=""><span ng-bind="$select.selected.fio"></span></ui-select-match>' +
24157				'<ui-select-choices ' +
24158					'class="ui-select-choices"' +
24159					'repeat="item in field.items track by item.id"' +
24160					'refresh="field.uiSelectOptions.refreshAutoComplete($select.search, \'Users\', \'users\')"' +
24161					'refresh-delay="0"' +
24162				'><span ng-bind="item.fio"></span><span ng-if="item.p0" ng-bind="item.p0"></span><span ng-if="item.p1" ng-bind="item.p1"></span></ui-select-choices>' +
24163			'</ui-select>'
24164		);
24165	}]);
24166
24167},{}],326:[function(require,module,exports){
24168'use strict';
24169
24170angular.module('dekky.forms.themes.far')
24171.run(["$templateCache", function($templateCache) {
24172	$templateCache.put('/dekky.forms/themes/far/row.html',
24173		'<span style="position: relative;">' +
24174			'<label for="{{ field.name }}" ng-if="field.label_before" ng-class="field.label_before_class">{{ field.label_before }}</label>' +
24175			'<form-widget field="field" ng-model="model" ng-disabled="disabled"></form-widget>' +
24176			'<label for="{{ field.name }}" ng-if="field.label && field.type != \'checkbox\'">{{ field.label }}</label>' +
24177		'</span>'
24178	);
24179}]);
24180
24181},{}],327:[function(require,module,exports){
24182'use strict';
24183
24184angular.module('dekky.forms.validators.collectionMaxlength', [])
24185	.directive('collectionMaxlength', function() {
24186		return {
24187			restrict: 'A',
24188			require: '?ngModel',
24189			link: function(scope, element, attr, ngModelController) {
24190				if (!ngModelController) {
24191					return;
24192				}
24193
24194				scope.$watch(
24195					function() {
24196						return ngModelController.$modelValue;
24197					},
24198					function () {
24199						ngModelController.$validate();
24200					},
24201					true
24202				);
24203
24204				ngModelController.$formatters.unshift(function(value) {
24205					ngModelController.$setValidity('collectionMaxlength', angular.isArray(value) && value.length <= attr.collectionMinlength);
24206
24207					return value;
24208				});
24209
24210				ngModelController.$parsers.unshift(function(value) {
24211					ngModelController.$setValidity('collectionMaxlength', angular.isArray(value) && value.length <= attr.collectionMinlength);
24212
24213					return value;
24214				});
24215
24216				ngModelController.$validators.collectionMaxlength = function(modelValue) {
24217					return angular.isArray(modelValue) && modelValue.length <= attr.collectionMinlength;
24218				};
24219			}
24220		}
24221	});
24222
24223},{}],328:[function(require,module,exports){
24224'use strict';
24225
24226angular.module('dekky.forms.validators.collectionMinlength', [])
24227.directive('collectionMinlength', function() {
24228	return {
24229		restrict: 'A',
24230		require: '?ngModel',
24231		link: function(scope, element, attr, ngModelController) {
24232			if (!ngModelController) {
24233				return;
24234			}
24235
24236			scope.$watch(
24237				function() {
24238					return ngModelController.$modelValue;
24239				},
24240				function () {
24241					ngModelController.$validate();
24242				},
24243				true
24244			);
24245
24246			ngModelController.$formatters.unshift(function(value) {
24247				ngModelController.$setValidity('collectionMinlength', angular.isArray(value) && value.length >= attr.collectionMinlength);
24248
24249				return value;
24250			});
24251
24252			ngModelController.$parsers.unshift(function(value) {
24253				ngModelController.$setValidity('collectionMinlength', angular.isArray(value) && value.length >= attr.collectionMinlength);
24254
24255				return value;
24256			});
24257
24258			ngModelController.$validators.collectionMinlength = function(modelValue) {
24259				return angular.isArray(modelValue) && modelValue.length >= attr.collectionMinlength;
24260			};
24261		}
24262	}
24263});
24264
24265},{}],329:[function(require,module,exports){
24266/**
24267 * Created by Phatbass on 25/02/16.
24268 */
24269
24270var email_regexp = /^[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/;
24271
24272angular.module('dekky.forms.validators.emailOnly', [])
24273    .directive('emailOnly', function(){
24274    return {
24275        require: '?ngModel',
24276        link: function(scope, element, attr, ngModelController) {
24277            ngModelController.$parsers.unshift(function (value) {
24278                if (email_regexp.test(value)) {
24279                    ngModelController.$setValidity('emailOnly', true);
24280                    return value;
24281                } else {
24282                    ngModelController.$setValidity('emailOnly', false);
24283
24284                    return undefined;
24285                }
24286            });
24287        }
24288    };
24289});
24290
24291},{}],330:[function(require,module,exports){
24292/**
24293 * Created by Phatbass on 25/02/16.
24294 */
24295
24296angular.module('dekky.forms.validators.numericOnly', [])
24297    .directive('numericOnly', function(){
24298    return {
24299        require: '?ngModel',
24300        link: function(scope, element, attr, ngModelController) {
24301
24302            ngModelController.$parsers.push(function (inputValue) {
24303                var transformedInput = inputValue ? inputValue.replace(/[^\d.]/g,'') : null;
24304
24305                if (transformedInput!=inputValue) {
24306                    ngModelController.$setViewValue(transformedInput);
24307                    ngModelController.$render();
24308                }
24309
24310                return transformedInput;
24311            });
24312        }
24313    };
24314});
24315
24316},{}],331:[function(require,module,exports){
24317/**
24318 * Created by Phatbass on 26/02/16.
24319 */
24320
24321var url_regexp = /(http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&amp;:\/~+#-]*[\w@?^=%&amp;\/~+#-])?/;
24322
24323angular.module('dekky.forms.validators.urlOnly', [])
24324    .directive('urlOnly', function() {
24325    return {
24326        require: '?ngModel',
24327        link: function(scope, element, attr, ngModelController) {
24328            ngModelController.$parsers.unshift(function (value) {
24329                if (url_regexp.test(value)) {
24330                    ngModelController.$setValidity('urlOnly', true);
24331                    return value;
24332                } else {
24333                    ngModelController.$setValidity('urlOnly', false);
24334
24335                    return undefined;
24336                }
24337            });
24338        }
24339    };
24340});
24341
24342},{}],332:[function(require,module,exports){
24343require('./gallery.module');
24344require('./gallery.service');
24345require('./gallery_edit.controller');
24346require('./gallery_show.controller');
24347
24348},{"./gallery.module":333,"./gallery.service":334,"./gallery_edit.controller":335,"./gallery_show.controller":336}],333:[function(require,module,exports){
24349'use strict';
24350
24351angular.module('far.gallery', ['angularFileUpload', 'dndLists']);
24352
24353},{}],334:[function(require,module,exports){
24354'use strict';
24355
24356var inheritArray = require('inherit-array');
24357
24358angular.module('far.gallery')
24359.service('gallery', ["$http", "$log", function($http, $log) {
24360
24361	function galleryProvider(term, id) {
24362		var factory = inheritArray(Gallery);
24363
24364		return factory(term, id);
24365	}
24366
24367	function Gallery(term, id) {
24368		var that = this;
24369
24370		this.term = term;
24371		this.id = id;
24372		this.progress = true;
24373		this.save = function() {
24374			var serverData = this.slice();
24375
24376			return $http.put(Routing.generate('api_gallery_put_gallery_object', {term: term, id: id}), serverData);
24377		};
24378		this.saveSort = function() {
24379			var serverData = this.slice();
24380
24381			return $http.patch(Routing.generate('api_gallery_patch_gallery_object_sort', {term: term, id: id}), serverData);
24382		};
24383
24384		$http.get(Routing.generate('api_gallery_get_gallery_object_items', {term: term, id: id}))
24385			.then(function(response) {
24386				response.data.items.forEach(function(item) {
24387					that.push(item);
24388				});
24389
24390				that.progress = false;
24391			})
24392			.catch(function(response) {
24393				$log.error('Error to get gallery for ' + term + ' ' + id, response);
24394				that.progress = false;
24395			});
24396	}
24397
24398	return galleryProvider;
24399}]);
24400
24401},{"inherit-array":7}],335:[function(require,module,exports){
24402'use strict';
24403
24404angular.module('far.gallery')
24405.controller('GalleryEditController', ["gallery", "FileUploader", function(gallery, FileUploader) {
24406	var uploader = new FileUploader({
24407		autoUpload: true,
24408		filters: [{
24409			name: 'images',
24410			fn: function(item) {
24411				return (/\.(gif|jpg|jpeg|tiff|png)$/i).test(item.name);
24412			}
24413		}],
24414		onSuccessItem: function (item, response) {
24415			item.server = response;
24416		}
24417	});
24418
24419	var vm = {
24420		getGallery: getGallery,
24421		uploader: uploader,
24422		gallerySave: gallerySave
24423	};
24424
24425	function getGallery(term, id) {
24426		vm.gallery = gallery(term, id);
24427		vm.uploader.url = Routing.generate('api_gallery_post_gallery_object_item', {term: vm.gallery.term, id: vm.gallery.id});
24428	}
24429
24430	function gallerySave() {
24431		var newItems = uploader.queue
24432			.filter(function(item) {
24433				return item.isUploaded;
24434			})
24435			.map(function(item) {
24436				return item.server;
24437			});
24438		uploader.clearQueue();
24439
24440		Array.prototype.push.apply(vm.gallery, newItems);
24441
24442		vm.gallery.save();
24443	}
24444
24445	return vm;
24446}]);
24447
24448},{}],336:[function(require,module,exports){
24449'use strict';
24450
24451angular.module('far.gallery')
24452.controller('GalleryShowController', ["gallery", function(gallery) {
24453	var vm = {
24454		getGallery: getGallery,
24455		saveSort: saveSort
24456	};
24457
24458	function getGallery(term, id) {
24459		vm.gallery = gallery(term, id);
24460	}
24461
24462	function saveSort(index) {
24463		vm.gallery.splice(index, 1);
24464		vm.gallery.saveSort();
24465	}
24466
24467	return vm;
24468}]);
24469
24470},{}],337:[function(require,module,exports){
24471'use strict';
24472
24473angular
24474.module('far.maps.geocoder', [])
24475.provider('Geocoder', function() {
24476  return {
24477    setConfig: function(srcConfig) {
24478      angular.extend(config, srcConfig);
24479    },
24480
24481    $get: ["$q", "uiGmapGoogleMapApi", function($q, uiGmapGoogleMapApi) {
24482      function Geocoder() {
24483        var geocoder, statusOk;
24484
24485        uiGmapGoogleMapApi.then(function(maps) {
24486          geocoder = new maps.Geocoder;
24487          statusOk = maps.GeocoderStatus.OK;
24488        });
24489
24490        this.geocode = function(locationObj, callback) {
24491          return $q(function(resolve, reject) {
24492            if (!geocoder) {
24493              return reject('Maps not initialized');
24494            }
24495
24496            geocoder.geocode(locationObj, function(results, status) {
24497              if (status == statusOk) {
24498                resolve({
24499                  result: results,
24500                  status: status
24501                });
24502              } else {
24503                reject({
24504                  result: results,
24505                  status: status
24506                });
24507              }
24508
24509              if (angular.isFunction(callback)) {
24510                callback(results, status);
24511              }
24512            });
24513          });
24514        }
24515
24516        this.getLocationsByAddress = function(address, callback) {
24517          return this.geocode({
24518            address: address
24519          }, callback);
24520        }
24521
24522        this.getLocationsByLocation = function(location, callback) {
24523          return this.geocode({
24524            location: location
24525          }, callback);
24526        }
24527
24528        this.getLocationsByPlaceId = function(placeId, callback) {
24529          return this.geocode({
24530            placeId: placeId
24531          }, callback);
24532        }
24533
24534        this.getLatLngObject = function(location) {
24535          return {
24536            latitude: location.lat(),
24537            longitude: location.lng()
24538          }
24539        }
24540      }
24541
24542      return Geocoder;
24543    }]
24544  };
24545});
24546
24547},{}],338:[function(require,module,exports){
24548require('./maps.module');
24549require('./maps.service');
24550
24551},{"./maps.module":339,"./maps.service":340}],339:[function(require,module,exports){
24552'use strict';
24553
24554require('./geocoder.service');
24555
24556angular.module('far.maps', ['uiGmapgoogle-maps', 'far.maps.geocoder', 'nemLogging'])
24557.config(["uiGmapGoogleMapApiProvider", function(uiGmapGoogleMapApiProvider){
24558  uiGmapGoogleMapApiProvider.configure({
24559      key: 'AIzaSyCrmpvXhsOxOUk2l5MEVMOWTexbTOPkag8',
24560      libraries: 'geometry,visualization'
24561  });
24562}]);
24563
24564},{"./geocoder.service":337}],340:[function(require,module,exports){
24565'use strict';
24566
24567angular.module('far.maps')
24568    .provider('maps', function () {
24569        var config = {
24570            defaultCenter: {
24571                latitude: 43.3499382,
24572                longitude: 42.44533009999998
24573            },
24574            defaultZoom: 10,
24575            style: [
24576                {
24577                    "featureType": "administrative",
24578                    "elementType": "all",
24579                    "stylers": [
24580                        {
24581                            "visibility": "on"
24582                        },
24583                        {
24584                            "lightness": 33
24585                        }
24586                    ]
24587                },
24588                {
24589                    "featureType": "administrative",
24590                    "elementType": "labels",
24591                    "stylers": [
24592                        {
24593                            "saturation": "-100"
24594                        }
24595                    ]
24596                },
24597                {
24598                    "featureType": "administrative",
24599                    "elementType": "labels.text",
24600                    "stylers": [
24601                        {
24602                            "gamma": "0.75"
24603                        }
24604                    ]
24605                },
24606                {
24607                    "featureType": "administrative.neighborhood",
24608                    "elementType": "labels.text.fill",
24609                    "stylers": [
24610                        {
24611                            "lightness": "-37"
24612                        }
24613                    ]
24614                },
24615                {
24616                    "featureType": "landscape",
24617                    "elementType": "geometry",
24618                    "stylers": [
24619                        {
24620                            "color": "#f9f9f9"
24621                        }
24622                    ]
24623                },
24624                {
24625                    "featureType": "landscape.man_made",
24626                    "elementType": "geometry",
24627                    "stylers": [
24628                        {
24629                            "saturation": "-100"
24630                        },
24631                        {
24632                            "lightness": "40"
24633                        },
24634                        {
24635                            "visibility": "off"
24636                        }
24637                    ]
24638                },
24639                {
24640                    "featureType": "landscape.natural",
24641                    "elementType": "labels.text.fill",
24642                    "stylers": [
24643                        {
24644                            "saturation": "-100"
24645                        },
24646                        {
24647                            "lightness": "-37"
24648                        }
24649                    ]
24650                },
24651                {
24652                    "featureType": "landscape.natural",
24653                    "elementType": "labels.text.stroke",
24654                    "stylers": [
24655                        {
24656                            "saturation": "-100"
24657                        },
24658                        {
24659                            "lightness": "100"
24660                        },
24661                        {
24662                            "weight": "2"
24663                        }
24664                    ]
24665                },
24666                {
24667                    "featureType": "landscape.natural",
24668                    "elementType": "labels.icon",
24669                    "stylers": [
24670                        {
24671                            "saturation": "-100"
24672                        }
24673                    ]
24674                },
24675                {
24676                    "featureType": "poi",
24677                    "elementType": "geometry",
24678                    "stylers": [
24679                        {
24680                            "saturation": "-100"
24681                        },
24682                        {
24683                            "lightness": "80"
24684                        }
24685                    ]
24686                },
24687                {
24688                    "featureType": "poi",
24689                    "elementType": "labels",
24690                    "stylers": [
24691                        {
24692                            "saturation": "-100"
24693                        },
24694                        {
24695                            "lightness": "0"
24696                        }
24697                    ]
24698                },
24699                {
24700                    "featureType": "poi.attraction",
24701                    "elementType": "geometry",
24702                    "stylers": [
24703                        {
24704                            "lightness": "-4"
24705                        },
24706                        {
24707                            "saturation": "-100"
24708                        }
24709                    ]
24710                },
24711                {
24712                    "featureType": "poi.park",
24713                    "elementType": "geometry",
24714                    "stylers": [
24715                        {
24716                            "color": "#c5dac6"
24717                        },
24718                        {
24719                            "visibility": "on"
24720                        },
24721                        {
24722                            "saturation": "-95"
24723                        },
24724                        {
24725                            "lightness": "62"
24726                        }
24727                    ]
24728                },
24729                {
24730                    "featureType": "poi.park",
24731                    "elementType": "labels",
24732                    "stylers": [
24733                        {
24734                            "visibility": "on"
24735                        },
24736                        {
24737                            "lightness": 20
24738                        }
24739                    ]
24740                },
24741                {
24742                    "featureType": "road",
24743                    "elementType": "all",
24744                    "stylers": [
24745                        {
24746                            "lightness": 20
24747                        }
24748                    ]
24749                },
24750                {
24751                    "featureType": "road",
24752                    "elementType": "labels",
24753                    "stylers": [
24754                        {
24755                            "saturation": "-100"
24756                        },
24757                        {
24758                            "gamma": "1.00"
24759                        }
24760                    ]
24761                },
24762                {
24763                    "featureType": "road",
24764                    "elementType": "labels.text",
24765                    "stylers": [
24766                        {
24767                            "gamma": "0.50"
24768                        }
24769                    ]
24770                },
24771                {
24772                    "featureType": "road",
24773                    "elementType": "labels.icon",
24774                    "stylers": [
24775                        {
24776                            "saturation": "-100"
24777                        },
24778                        {
24779                            "gamma": "0.50"
24780                        }
24781                    ]
24782                },
24783                {
24784                    "featureType": "road.highway",
24785                    "elementType": "geometry",
24786                    "stylers": [
24787                        {
24788                            "color": "#c5c6c6"
24789                        },
24790                        {
24791                            "saturation": "-100"
24792                        }
24793                    ]
24794                },
24795                {
24796                    "featureType": "road.highway",
24797                    "elementType": "geometry.stroke",
24798                    "stylers": [
24799                        {
24800                            "lightness": "-13"
24801                        }
24802                    ]
24803                },
24804                {
24805                    "featureType": "road.highway",
24806                    "elementType": "labels.icon",
24807                    "stylers": [
24808                        {
24809                            "lightness": "0"
24810                        },
24811                        {
24812                            "gamma": "1.09"
24813                        }
24814                    ]
24815                },
24816                {
24817                    "featureType": "road.arterial",
24818                    "elementType": "geometry",
24819                    "stylers": [
24820                        {
24821                            "color": "#e4d7c6"
24822                        },
24823                        {
24824                            "saturation": "-100"
24825                        },
24826                        {
24827                            "lightness": "47"
24828                        }
24829                    ]
24830                },
24831                {
24832                    "featureType": "road.arterial",
24833                    "elementType": "geometry.stroke",
24834                    "stylers": [
24835                        {
24836                            "lightness": "-12"
24837                        }
24838                    ]
24839                },
24840                {
24841                    "featureType": "road.arterial",
24842                    "elementType": "labels.icon",
24843                    "stylers": [
24844                        {
24845                            "saturation": "-100"
24846                        }
24847                    ]
24848                },
24849                {
24850                    "featureType": "road.local",
24851                    "elementType": "geometry",
24852                    "stylers": [
24853                        {
24854                            "color": "#fbfaf7"
24855                        },
24856                        {
24857                            "lightness": "77"
24858                        }
24859                    ]
24860                },
24861                {
24862                    "featureType": "road.local",
24863                    "elementType": "geometry.fill",
24864                    "stylers": [
24865                        {
24866                            "lightness": "-5"
24867                        },
24868                        {
24869                            "saturation": "-100"
24870                        }
24871                    ]
24872                },
24873                {
24874                    "featureType": "road.local",
24875                    "elementType": "geometry.stroke",
24876                    "stylers": [
24877                        {
24878                            "saturation": "-100"
24879                        },
24880                        {
24881                            "lightness": "-15"
24882                        }
24883                    ]
24884                },
24885                {
24886                    "featureType": "transit.station.airport",
24887                    "elementType": "geometry",
24888                    "stylers": [
24889                        {
24890                            "lightness": "47"
24891                        },
24892                        {
24893                            "saturation": "-100"
24894                        }
24895                    ]
24896                },
24897                {
24898                    "featureType": "water",
24899                    "elementType": "all",
24900                    "stylers": [
24901                        {
24902                            "visibility": "on"
24903                        },
24904                        {
24905                            "color": "#acbcc9"
24906                        }
24907                    ]
24908                },
24909                {
24910                    "featureType": "water",
24911                    "elementType": "geometry",
24912                    "stylers": [
24913                        {
24914                            "saturation": "53"
24915                        }
24916                    ]
24917                },
24918                {
24919                    "featureType": "water",
24920                    "elementType": "labels.text.fill",
24921                    "stylers": [
24922                        {
24923                            "lightness": "-42"
24924                        },
24925                        {
24926                            "saturation": "17"
24927                        }
24928                    ]
24929                },
24930                {
24931                    "featureType": "water",
24932                    "elementType": "labels.text.stroke",
24933                    "stylers": [
24934                        {
24935                            "lightness": "61"
24936                        }
24937                    ]
24938                }
24939            ]
24940        };
24941
24942       
24942 return {
24943            setConfig: function (customConfig) {
24944                config = angular.extend(config, customConfig);
24945            },
24946
24947            setDefaultCenter: function (center) {
24948                config.defaultCenter = center;
24949            },
24950
24951            setDefaultZoom: function (zoom) {
24952                config.defaultZoom = zoom;
24953            },
24954
24955            $get: function () {
24956                return {
24957                    getDefaultCenter: function () {
24958                        return config.defaultCenter;
24959                    },
24960
24961                    getDefaultZoom: function () {
24962                        return config.defaultZoom;
24963                    },
24964
24965                    getStyle: function () {
24966                        return config.style;
24967                    }
24968                }
24969            }
24970        };
24971    });
24972
24973},{}],341:[function(require,module,exports){
24974'use strict';
24975
24976var inheritArray = require('inherit-array');
24977
24978angular.module('dekky.pagination', [])
24979.provider('pagination', function() {
24980	var defaultConfig = {
24981		itemsOnPage: 10,
24982		type: 'endless',
24983		next: null
24984	};
24985
24986	return {
24987		setItemsOnPage: function(count) {
24988			defaultConfig.itemsOnPage = count;
24989		},
24990		$get: ["$q", function($q) {
24991			function collectionFactory(name, config) {
24992				var factory = inheritArray(Collection);
24993				return factory(name, config);
24994			}
24995
24996			function Collection(name, config) {
24997				this.config = angular.merge({}, defaultConfig, config);
24998				this.name = name;
24999				this.progress = false;
25000				this.current_page = 0;
25001			}
25002
25003			Collection.prototype.next = function() {
25004				var that = this;
25005				if (typeof(that.config.next) == 'function') {
25006					that.progress = true;
25007
25008					return that.config.next(++that.current_page, that.config.itemsOnPage)
25009						.then(function(response){
25010							response.forEach(function(item) {
25011								that.push(item);
25012							});
25013							that.progress = false;
25014
25015							return $q.when(response);
25016						})
25017						.catch(function(response) {
25018							that.current_page--;
25019							that.progress = false;
25020
25021							return $q.reject(response);
25022						});
25023				}
25024			};
25025
25026			Collection.prototype.clear = function() {
25027				this.length = 0;
25028				this.current_page = 0;
25029				this.next();
25030			};
25031
25032			Collection.prototype.changeItemsOnPage = function(itemsOnPage) {
25033				this.config.itemsOnPage = itemsOnPage;
25034				this.clear();
25035			};
25036
25037			return collectionFactory;
25038		}]
25039	}
25040});
25041
25042},{"inherit-array":7}],342:[function(require,module,exports){
25043'use strict';
25044
25045angular.module('far.ui.eventsCalendar')
25046.directive('eventsCalendar', ["$timeout", "eventsCalendarConfig", function($timeout, eventsCalendarConfig) {
25047    function getDaysInMonth(date) {
25048        return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
25049    }
25050
25051    function getWeeksInMonth(date) {
25052        var maxDays = getDaysInMonth(date) + getFirstDayOfMonth(date);
25053
25054        return Math.ceil(maxDays / 7);
25055    }
25056
25057    function getFirstDayOfMonth(date) {
25058        var firstDate = new Date(date),
25059            firstDayOfMonth;
25060
25061        firstDate.setDate(1);
25062        firstDayOfMonth = firstDate.getDay();
25063
25064        return firstDayOfMonth > 0 ? --firstDayOfMonth : 6;
25065    }
25066
25067    function getMonthArray(date) {
25068        var weeksInMonth = getWeeksInMonth(date),
25069            firstDay = getFirstDayOfMonth(date),
25070            maxDays = getDaysInMonth(date) + firstDay,
25071            monthArray = [];
25072
25073        for (var week = 0; week < weeksInMonth; week++) {
25074            var weekArray = [];
25075
25076            for (var weekday = 0; weekday < 7; weekday++) {
25077                var monthDay = week * 7 + weekday;
25078
25079                if (monthDay < firstDay) {
25080                    weekArray.push(null);
25081                    continue;
25082                }
25083
25084                if (monthDay >= maxDays) {
25085                    weekArray.push(null);
25086                    continue;
25087                }
25088
25089                weekArray.push(monthDay - firstDay + 1);
25090            }
25091
25092            monthArray.push(weekArray);
25093        }
25094
25095        return monthArray;
25096    }
25097
25098    return {
25099        restrict: 'EA',
25100        templateUrl: '/modules/ui/events-calendar/events-calendar.html',
25101        scope: {
25102            events: '='
25103        },
25104        link: function(scope, attrs) {
25105            scope.maxMonths = 11;
25106            scope.monthDiff = 0;
25107            scope.days = eventsCalendarConfig.days;
25108            scope.month = new Date();
25109            scope.month.setDate(1);
25110
25111            if (attrs.maxMonths && attrs.maxMonths > 0) {
25112                scope.maxMonths = attrs.maxMonths;
25113            }
25114
25115            setScopeCurrentMonth();
25116
25117            scope.nextMonth = function() {
25118                if (scope.monthDiff >= scope.maxMonths) {
25119                    return;
25120                }
25121
25122                scope.monthDiff++;
25123                scope.month.setMonth(scope.month.getMonth() + 1);
25124                setScopeCurrentMonth();
25125            };
25126
25127            scope.prevMonth = function() {
25128                if (scope.monthDiff == 0) {
25129                    return;
25130                }
25131
25132                scope.monthDiff--;
25133                scope.month.setMonth(scope.month.getMonth() - 1);
25134                setScopeCurrentMonth();
25135            };
25136
25137            scope.isEventsOnDate = function(day) {
25138                if (day == null) {
25139                    return false;
25140                }
25141
25142                var monthString = (scope.month.getMonth() + 1) > 9 ? scope.month.getMonth() + 1 : ('0' + (scope.month.getMonth() + 1)),
25143                    dayString = day > 9 ? day : ('0' + day),
25144                    dateString = scope.month.getFullYear() + '' + monthString + '' + dayString;
25145
25146                return angular.isDefined(scope.events[dateString]);
25147            };
25148
25149            scope.getEventsOnDate = function(day) {
25150                var monthString = (scope.month.getMonth() + 1) > 9 ? scope.month.getMonth() + 1 : ('0' + (scope.month.getMonth() + 1)),
25151                    dayString = day > 9 ? day : ('0' + day),
25152                    dateString = scope.month.getFullYear() + '' + monthString + '' + dayString;
25153
25154                return scope.events[dateString];
25155            };
25156
25157            function setScopeCurrentMonth() {
25158                scope.monthName = eventsCalendarConfig.months[scope.month.getMonth()];
25159                scope.monthArray = getMonthArray(scope.month);
25160            }
25161        }
25162    };
25163}]);
25164
25165},{}],343:[function(require,module,exports){
25166var ngModule;
25167try {
25168  ngModule = angular.module('templates');
25169} catch (e) {
25170  ngModule = angular.module('templates', []);
25171}
25172
25173ngModule.run(['$templateCache', function ($templateCache) {
25174  $templateCache.put('/modules/ui/events-calendar/events-calendar.html',
25175    '<div class="events-calendar">\n' +
25176    '    <div class="events-calendar__header">\n' +
25177    '        <button class="events-calendar__btn-prev" ng-click="prevMonth()" ng-if="monthDiff > 0">&#10094;</button>\n' +
25178    '        <span class="events-calendar__month-name">{{ monthName }}</span>\n' +
25179    '        <button class="events-calendar__btn-next" ng-click="nextMonth()" ng-if="monthDiff < maxMonths">&#10095;</button>\n' +
25180    '    </div>\n' +
25181    '    <div class="events-calendar__body">\n' +
25182    '        <table class="events-calendar__calendar">\n' +
25183    '            <thead class="events-calendar__weekday">\n' +
25184    '                <tr>\n' +
25185    '                    <th ng-repeat="dayName in days">{{ dayName }}</th>\n' +
25186    '                </tr>\n' +
25187    '            </thead>\n' +
25188    '            <tbody>\n' +
25189    '                <tr ng-repeat="week in monthArray track by $index">\n' +
25190    '                    <td ng-repeat="day in week track by $index">\n' +
25191    '                        <span class="events-calendar__day" ng-if="!isEventsOnDate(day)">{{ day }}</span>\n' +
25192    '                        <span class="events-calendar__day events-calendar__day--with-events"\n' +
25193    '                              ng-if="isEventsOnDate(day)">{{ day }}\n' +
25194    '                            <ul class="events-calendar__events">\n' +
25195    '                                <li ng-repeat="event in getEventsOnDate(day) track by $index">\n' +
25196    '                                    <a ng-href="{{ event.url }}" class="btn-link">{{ event.name }}</a>\n' +
25197    '                                </li>\n' +
25198    '                            </ul>\n' +
25199    '                        </span>\n' +
25200    '                    </td>\n' +
25201    '                </tr>\n' +
25202    '            </tbody>\n' +
25203    '        </table>\n' +
25204    '    </div>\n' +
25205    '</div>');
25206}]);
25207
25208module.exports = "/modules/ui/events-calendar/events-calendar.html";
25209},{}],344:[function(require,module,exports){
25210require('./events-calendar.module');
25211require('./events-calendar.directive');
25212require('./events-calendar.html');
25213
25214},{"./events-calendar.directive":342,"./events-calendar.html":343,"./events-calendar.module":345}],345:[function(require,module,exports){
25215'use strict';
25216
25217angular.module('far.ui.eventsCalendar', [])
25218.constant('eventsCalendarConfig', {
25219    months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
25220    days: ['пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'вс']
25221});
25222
25223},{}],346:[function(require,module,exports){
25224'use strict';
25225
25226angular.module('far.ui.readMoreBtn', [])
25227.directive('readMoreBtn', ["$timeout", function($timeout) {
25228  return {
25229    restrict: 'A',
25230    link: function(scope, element, attr) {
25231      var minHeight = attr.readMoreBtn || 100,
25232          btnTemplate, btnElement, openElement, closeElement;
25233
25234      $timeout(function() {
25235        if (element[0].clientHeight <= minHeight) {
25236          return;
25237        }
25238
25239        btnTemplate =
25240         '<div class="read-more-btn">' +
25241           '<span class="read-more-btn__open">Читать далее</span>' +
25242           '<span class="read-more-btn__close">Свернуть</span>' +
25243         '</div>';
25244
25245        btnElement = angular.element(btnTemplate);
25246        openElement = angular.element(btnElement[0].getElementsByClassName('read-more-btn__open'));
25247        closeElement = angular.element(btnElement[0].getElementsByClassName('read-more-btn__close'));
25248
25249        openElement.on('click', function() {
25250          element.removeClass('closed');
25251        });
25252        closeElement.on('click', function() {
25253          element.addClass('closed');
25254        });
25255
25256        element.addClass('closed with-animation');
25257        element.append(btnElement);
25258      });
25259    }
25260  }
25261}]);
25262
25263},{}],347:[function(require,module,exports){
25264require('./ui.module');
25265
25266},{"./ui.module":348}],348:[function(require,module,exports){
25267'use strict';
25268
25269require('./read-more-btn/read-more-btn');
25270require('./events-calendar/events-calendar');
25271
25272angular.module('far.ui', [
25273  'far.ui.readMoreBtn',
25274  'far.ui.eventsCalendar'
25275]);
25276
25277},{"./events-calendar/events-calendar":344,"./read-more-btn/read-more-btn":346}],349:[function(require,module,exports){
25278$.Redactor.opts.langs['ru'] = {
25279    html: 'Код',
25280    video: 'Видео',
25281    image: 'Изображение',
25282    table: 'Таблица',
25283    link: 'Ссылка',
25284    link_insert: 'Вставить ссылку ...',
25285    link_edit: 'Изменить ссылку',
25286    unlink: 'Удалить ссылку',
25287    formatting: 'Форматирование',
25288    paragraph: 'Обычный текст',
25289    quote: 'Цитата',
25290    code: 'Код',
25291    header1: 'Заголовок 1',
25292    header2: 'Заголовок 2',
25293    header3: 'Заголовок 3',
25294    header4: 'Заголовок 4',
25295    header5: 'Заголовок 5',
25296    bold: 'Полужирный',
25297    italic: 'Наклонный',
25298    fontcolor: 'Цвет текста',
25299    backcolor: 'Заливка текста',
25300    unorderedlist: 'Обычный список',
25301    orderedlist: 'Нумерованный список',
25302    outdent: 'Уменьшить отступ',
25303    indent: 'Увеличить отступ',
25304    cancel: 'Отменить',
25305    insert: 'Вставить',
25306    save: 'Сохранить',
25307    _delete: 'Удалить',
25308    insert_table: 'Вставить таблицу',
25309    insert_row_above: 'Добавить строку сверху',
25310    insert_row_below: 'Добавить строку снизу',
25311    insert_column_left: 'Добавить столбец слева',
25312    insert_column_right: 'Добавить столбец справа',
25313    delete_column: 'Удалить столбец',
25314    delete_row: 'Удалить строку',
25315    delete_table: 'Удалить таблицу',
25316    rows: 'Строки',
25317    columns: 'Столбцы',
25318    add_head: 'Добавить заголовок',
25319    delete_head: 'Удалить заголовок',
25320    title: 'Подсказка',
25321    image_position: 'Обтекание текстом',
25322    none: 'Нет',
25323    left: 'Cлева',
25324    right: 'Cправа',
25325    image_web_link: 'Cсылка на изображение',
25326    text: 'Текст',
25327    mailto: 'Эл. почта',
25328    web: 'URL',
25329    video_html_code: 'Код видео ролика',
25330    file: 'Файл',
25331    upload: 'Загрузить',
25332    download: 'Скачать',
25333    choose: 'Выбрать',
25334    or_choose: 'Или выберите',
25335    drop_file_here: 'Перетащите файл сюда',
25336    align_left: 'По левому краю',
25337    align_center: 'По центру',
25338    align_right: 'По правому краю',
25339    align_justify: 'Выровнять текст по ширине',
25340    horizontalrule: 'Горизонтальная линейка',
25341    fullscreen: 'Во весь экран',
25342    deleted: 'Зачеркнутый',
25343    anchor: 'Якорь',
25344    link_new_tab: 'Открывать в новой вкладке',
25345    underline: 'Подчеркнутый',
25346    alignment: 'Выравнивание',
25347    filename: 'Название (необязательно)',
25348    edit: 'Ред.',
25349    center: 'По центру',
25350    upload_label: 'Drop file here or '
25351};
25352
25353},{}],350:[function(require,module,exports){
25354/*
25355	Redactor 10.2.5
25356	Updated: October 1, 2015
25357
25358	http://imperavi.com/redactor/
25359
25360	Copyright (c) 2009-2015, Imperavi LLC.
25361	License: http://imperavi.com/redactor/license/
25362
25363	Usage: $('#content').redactor();
25364*/
25365
25366(function($)
25367{
25368
25369	'use strict';
25370
25371	if (!Function.prototype.bind)
25372	{
25373		Function.prototype.bind = function(scope)
25374		{
25375			var fn = this;
25376			return function()
25377			{
25378				return fn.apply(scope);
25379			};
25380		};
25381	}
25382
25383	var uuid = 0;
25384
25385	// Plugin
25386	$.fn.redactor = function(options)
25387	{
25388		var val = [];
25389		var args = Array.prototype.slice.call(arguments, 1);
25390
25391		if (typeof options === 'string')
25392		{
25393			this.each(function()
25394			{
25395				var instance = $.data(this, 'redactor');
25396				var func;
25397
25398				if (options.search(/\./) != '-1')
25399				{
25400					func = options.split('.');
25401					if (typeof instance[func[0]] != 'undefined')
25402					{
25403						func = instance[func[0]][func[1]];
25404					}
25405				}
25406				else
25407				{
25408					func = instance[options];
25409				}
25410
25411				if (typeof instance !== 'undefined' && $.isFunction(func))
25412				{
25413					var methodVal = func.apply(instance, args);
25414					if (methodVal !== undefined && methodVal !== instance)
25415					{
25416						val.push(methodVal);
25417					}
25418				}
25419				else
25420				{
25421					$.error('No such method "' + options + '" for Redactor');
25422				}
25423			});
25424		}
25425		else
25426		{
25427			this.each(function()
25428			{
25429				$.data(this, 'redactor', {});
25430				$.data(this, 'redactor', Redactor(this, options));
25431			});
25432		}
25433
25434		if (val.length === 0) return this;
25435		else if (val.length === 1) return val[0];
25436		else return val;
25437
25438	};
25439
25440	// Initialization
25441	function Redactor(el, options)
25442	{
25443		return new Redactor.prototype.init(el, options);
25444	}
25445
25446	// Functionality
25447	$.Redactor = Redactor;
25448	$.Redactor.VERSION = '10.2.5';
25449	$.Redactor.modules = ['alignment', 'autosave', 'block', 'buffer', 'build', 'button',
25450						  'caret', 'clean', 'code', 'core', 'dropdown', 'file', 'focus',
25451						  'image', 'indent', 'inline', 'insert', 'keydown', 'keyup',
25452						  'lang', 'line', 'link', 'linkify', 'list', 'modal', 'observe', 'paragraphize',
25453						  'paste', 'placeholder', 'progress', 'selection', 'shortcuts',
25454						  'tabifier', 'tidy',  'toolbar', 'upload', 'utils'];
25455
25456	$.Redactor.opts = {
25457
25458		// settings
25459		lang: 'en',
25460		direction: 'ltr', // ltr or rtl
25461
25462		plugins: false, // array
25463
25464		focus: false,
25465		focusEnd: false,
25466
25467		placeholder: false,
25468
25469		visual: true,
25470		tabindex: false,
25471
25472		minHeight: false,
25473		maxHeight: false,
25474
25475		linebreaks: false,
25476		replaceDivs: true,
25477		paragraphize: true,
25478		cleanStyleOnEnter: false,
25479		enterKey: true,
25480
25481		cleanOnPaste: true,
25482		cleanSpaces: true,
25483		pastePlainText: false,
25484
25485		autosave: false, // false or url
25486		autosaveName: false,
25487		autosaveInterval: 60, // seconds
25488		autosaveOnChange: false,
25489		autosaveFields: false,
25490
25491		linkTooltip: true,
25492		linkProtocol: 'http',
25493		linkNofollow: false,
25494		linkSize: 50,
25495
25496		imageEditable: true,
25497		imageLink: true,
25498		imagePosition: true,
25499		imageFloatMargin: '10px',
25500		imageResizable: true,
25501
25502		imageUpload: null,
25503		imageUploadParam: 'file',
25504
25505		uploadImageField: false,
25506
25507		dragImageUpload: true,
25508
25509		fileUpload: null,
25510		fileUploadParam: 'file',
25511
25512		dragFileUpload: true,
25513
25514		s3: false,
25515
25516		convertLinks: true,
25517		convertUrlLinks: true,
25518		convertImageLinks: true,
25519		convertVideoLinks: true,
25520
25521		preSpaces: 4, // or false
25522		tabAsSpaces: false, // true or number of spaces
25523		tabKey: true,
25524
25525		scrollTarget: false,
25526
25527		toolbar: true,
25528		toolbarFixed: true,
25529		toolbarFixedTarget: document,
25530		toolbarFixedTopOffset: 0, // pixels
25531		toolbarExternal: false, // ID selector
25532		toolbarOverflow: false,
25533
25534		source: true,
25535		buttons: ['html', 'table','formatting', 'bold', 'italic', 'deleted', 'unorderedlist', 'orderedlist',
25536				  'outdent', 'indent', 'image', 'file', 'link', 'alignment', 'horizontalrule'], // + 'underline'
25537
25538		buttonsHide: [],
25539		buttonsHideOnMobile: [],
25540
25541		formatting: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
25542		formattingAdd: false,
25543
25544		tabifier: true,
25545
25546		deniedTags: ['script', 'style'],
25547		allowedTags: false, // or array
25548
25549		paragraphizeBlocks: ['table', 'div', 'pre', 'form', 'ul', 'ol', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'dl', 'blockquote', 'figcaption',
25550							'address', 'section', 'header', 'footer', 'aside', 'article', 'object', 'style', 'script', 'iframe', 'select', 'input', 'textarea',
25551							'button', 'option', 'map', 'area', 'math', 'hr', 'fieldset', 'legend', 'hgroup', 'nav', 'figure', 'details', 'menu', 'summary', 'p'],
25552
25553		removeComments: false,
25554		replaceTags: [
25555			['strike', 'del'],
25556			['b', 'strong']
25557		],
25558		replaceStyles: [
25559            ['font-weight:\\s?bold', "strong"],
25560            ['font-style:\\s?italic', "em"],
25561            ['text-decoration:\\s?underline', "u"],
25562            ['text-decoration:\\s?line-through', 'del']
25563        ],
25564        removeDataAttr: false,
25565
25566		removeAttr: false, // or multi array
25567		allowedAttr: false, // or multi array
25568
25569		removeWithoutAttr: ['span'], // or false
25570		removeEmpty: ['p'], // or false;
25571
25572		activeButtons: ['deleted', 'italic', 'bold', 'underline', 'unorderedlist', 'orderedlist',
25573						'alignleft', 'aligncenter', 'alignright', 'justify'],
25574		activeButtonsStates: {
25575			b: 'bold',
25576			strong: 'bold',
25577			i: 'italic',
25578			em: 'italic',
25579			del: 'deleted',
25580			strike: 'deleted',
25581			ul: 'unorderedlist',
25582			ol: 'orderedlist',
25583			u: 'underline'
25584		},
25585
25586		shortcuts: {
25587			'ctrl+shift+m, meta+shift+m': { func: 'inline.removeFormat' },
25588			'ctrl+b, meta+b': { func: 'inline.format', params: ['bold'] },
25589			'ctrl+i, meta+i': { func: 'inline.format', params: ['italic'] },
25590			'ctrl+h, meta+h': { func: 'inline.format', params: ['superscript'] },
25591			'ctrl+l, meta+l': { func: 'inline.format', params: ['subscript'] },
25592			'ctrl+k, meta+k': { func: 'link.show' },
25593			'ctrl+shift+7':   { func: 'list.toggle', params: ['orderedlist'] },
25594			'ctrl+shift+8':   { func: 'list.toggle', params: ['unorderedlist'] }
25595		},
25596		shortcutsAdd: false,
25597
25598		// private
25599		buffer: [],
25600		rebuffer: [],
25601		emptyHtml: '<p>&#x200b;</p>',
25602		invisibleSpace: '&#x200b;',
25603		imageTypes: ['image/png', 'image/jpeg', 'image/gif'],
25604		indentValue: 20,
25605		verifiedTags: 		['a', 'img', 'b', 'strong', 'sub', 'sup', 'i', 'em', 'u', 'small', 'strike', 'del', 'cite', 'ul', 'ol', 'li'], // and for span tag special rule
25606		inlineTags: 		['strong', 'b', 'u', 'em', 'i', 'code', 'del', 'ins', 'samp', 'kbd', 'sup', 'sub', 'mark', 'var', 'cite', 'small'],
25607		alignmentTags: 		['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6',  'DL', 'DT', 'DD', 'DIV', 'TD', 'BLOCKQUOTE', 'OUTPUT', 'FIGCAPTION', 'ADDRESS', 'SECTION', 'HEADER', 'FOOTER', 'ASIDE', 'ARTICLE'],
25608		blockLevelElements: ['PRE', 'UL', 'OL', 'LI'],
25609		highContrast: false,
25610		observe: {
25611			dropdowns: []
25612		},
25613
25614		// lang
25615		langs: {
25616			en: {
25617				html: 'HTML',
25618				video: 'Insert Video',
25619				image: 'Insert Image',
25620				table: 'Table',
25621				link: 'Link',
25622				link_insert: 'Insert link',
25623				link_edit: 'Edit link',
25624				unlink: 'Unlink',
25625				formatting: 'Formatting',
25626				paragraph: 'Normal text',
25627				quote: 'Quote',
25628				code: 'Code',
25629				header1: 'Header 1',
25630				header2: 'Header 2',
25631				header3: 'Header 3',
25632				header4: 'Header 4',
25633				header5: 'Header 5',
25634				bold: 'Bold',
25635				italic: 'Italic',
25636				fontcolor: 'Font Color',
25637				backcolor: 'Back Color',
25638				unorderedlist: 'Unordered List',
25639				orderedlist: 'Ordered List',
25640				outdent: 'Outdent',
25641				indent: 'Indent',
25642				cancel: 'Cancel',
25643				insert: 'Insert',
25644				save: 'Save',
25645				_delete: 'Delete',
25646				insert_table: 'Insert Table',
25647				insert_row_above: 'Add Row Above',
25648				insert_row_below: 'Add Row Below',
25649				insert_column_left: 'Add Column Left',
25650				insert_column_right: 'Add Column Right',
25651				delete_column: 'Delete Column',
25652				delete_row: 'Delete Row',
25653				delete_table: 'Delete Table',
25654				rows: 'Rows',
25655				columns: 'Columns',
25656				add_head: 'Add Head',
25657				delete_head: 'Delete Head',
25658				title: 'Title',
25659				image_position: 'Position',
25660				none: 'None',
25661				left: 'Left',
25662				right: 'Right',
25663				center: 'Center',
25664				image_web_link: 'Image Web Link',
25665				text: 'Text',
25666				mailto: 'Email',
25667				web: 'URL',
25668				video_html_code: 'Video Embed Code or Youtube/Vimeo Link',
25669				file: 'Insert File',
25670				upload: 'Upload',
25671				download: 'Download',
25672				choose: 'Choose',
25673				or_choose: 'Or choose',
25674				drop_file_here: 'Drop file here',
25675				align_left: 'Align text to the left',
25676				align_center: 'Center text',
25677				align_right: 'Align text to the right',
25678				align_justify: 'Justify text',
25679				horizontalrule: 'Insert Horizontal Rule',
25680				deleted: 'Deleted',
25681				anchor: 'Anchor',
25682				link_new_tab: 'Open link in new tab',
25683				underline: 'Underline',
25684				alignment: 'Alignment',
25685				filename: 'Name (optional)',
25686				edit: 'Edit',
25687				upload_label: 'Drop file here or '
25688			}
25689		},
25690
25691		linkify: {
25692			regexps: {
25693				youtube: /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.\-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig,
25694				vimeo: /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/,
25695				image: /((https?|www)[^\s]+\.)(jpe?g|png|gif)(\?[^\s-]+)?/ig,
25696				url: /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/ig,
25697			}
25698		},
25699
25700		codemirror: false
25701	};
25702
25703	// Functionality
25704	Redactor.fn = $.Redactor.prototype = {
25705
25706		keyCode: {
25707			BACKSPACE: 8,
25708			DELETE: 46,
25709			UP: 38,
25710			DOWN: 40,
25711			ENTER: 13,
25712			SPACE: 32,
25713			ESC: 27,
25714			TAB: 9,
25715			CTRL: 17,
25716			META: 91,
25717			SHIFT: 16,
25718			ALT: 18,
25719			RIGHT: 39,
25720			LEFT: 37,
25721			LEFT_WIN: 91
25722		},
25723
25724		// Initialization
25725		init: function(el, options)
25726		{
25727			this.$element = $(el);
25728			this.uuid = uuid++;
25729
25730			// if paste event detected = true
25731			this.rtePaste = false;
25732			this.$pasteBox = false;
25733
25734			this.loadOptions(options);
25735			this.loadModules();
25736
25737			// formatting storage
25738			this.formatting = {};
25739
25740			// block level tags
25741			$.merge(this.opts.blockLevelElements, this.opts.alignmentTags);
25742			this.reIsBlock = new RegExp('^(' + this.opts.blockLevelElements.join('|' ) + ')$', 'i');
25743
25744			// setup allowed and denied tags
25745			this.tidy.setupAllowed();
25746
25747			// setup denied tags
25748			if (this.opts.deniedTags !== false)
25749			{
25750				var tags = ['html', 'head', 'link', 'body', 'meta', 'applet'];
25751				for (var i = 0; i < tags.length; i++)
25752				{
25753					this.opts.deniedTags.push(tags[i]);
25754				}
25755			}
25756
25757			// load lang
25758			this.lang.load();
25759
25760			// extend shortcuts
25761			$.extend(this.opts.shortcuts, this.opts.shortcutsAdd);
25762
25763			// start callback
25764			this.core.setCallback('start');
25765
25766			// build
25767			this.start = true;
25768			this.build.run();
25769		},
25770
25771		loadOptions: function(options)
25772		{
25773			this.opts = $.extend(
25774				{},
25775				$.extend(true, {}, $.Redactor.opts),
25776				this.$element.data(),
25777				options
25778			);
25779		},
25780		getModuleMethods: function(object)
25781		{
25782			return Object.getOwnPropertyNames(object).filter(function(property)
25783			{
25784				return typeof object[property] == 'function';
25785			});
25786		},
25787		loadModules: function()
25788		{
25789			var len = $.Redactor.modules.length;
25790			for (var i = 0; i < len; i++)
25791			{
25792				this.bindModuleMethods($.Redactor.modules[i]);
25793			}
25794		},
25795		bindModuleMethods: function(module)
25796		{
25797			if (typeof this[module] == 'undefined') return;
25798
25799			// init module
25800			this[module] = this[module]();
25801
25802			var methods = this.getModuleMethods(this[module]);
25803			var len = methods.length;
25804
25805			// bind methods
25806			for (var z = 0; z < len; z++)
25807			{
25808				this[module][methods[z]] = this[module][methods[z]].bind(this);
25809			}
25810		},
25811		alignment: function()
25812		{
25813			return {
25814				left: function()
25815				{
25816					this.alignment.set('');
25817				},
25818				right: function()
25819				{
25820					this.alignment.set('right');
25821				},
25822				center: function()
25823				{
25824					this.alignment.set('center');
25825				},
25826				justify: function()
25827				{
25828					this.alignment.set('justify');
25829				},
25830				set: function(type)
25831				{
25832					// focus
25833					if (!this.utils.browser('msie') && !this.opts.linebreaks)
25834					{
25835						this.$editor.focus();
25836					}
25837
25838					// get blocks
25839					this.alignment.blocks = this.selection.getBlocks();
25840					this.alignment.type = type;
25841
25842					this.buffer.set();
25843					this.selection.save();
25844
25845					// set alignment
25846					if (this.alignment.isLinebreaksOrNoBlocks())
25847					{
25848						this.alignment.setText();
25849					}
25850					else
25851					{
25852						this.alignment.setBlocks();
25853					}
25854
25855					// sync
25856					this.selection.restore();
25857					this.code.sync();
25858				},
25859				setText: function()
25860				{
25861					var wrapper = this.selection.wrap('div');
25862					$(wrapper).attr('data-tagblock', 'redactor').css('text-align', this.alignment.type);
25863				},
25864				setBlocks: function()
25865				{
25866					$.each(this.alignment.blocks, $.proxy(function(i, el)
25867					{
25868						var $el = this.utils.getAlignmentElement(el);
25869						if (!$el) return;
25870
25871						if (this.alignment.isNeedReplaceElement($el))
25872						{
25873							this.alignment.replaceElement($el);
25874						}
25875						else
25876						{
25877							this.alignment.alignElement($el);
25878						}
25879
25880					}, this));
25881				},
25882				isLinebreaksOrNoBlocks: function()
25883				{
25884					return (this.opts.linebreaks && this.alignment.blocks[0] === false);
25885				},
25886				isNeedReplaceElement: function($el)
25887				{
25888					return (this.alignment.type === '' && typeof($el.data('tagblock')) !== 'undefined');
25889				},
25890				replaceElement: function($el)
25891				{
25892					$el.replaceWith($el.html());
25893				},
25894				alignElement: function($el)
25895				{
25896					$el.css('text-align', this.alignment.type);
25897					this.utils.removeEmptyAttr($el, 'style');
25898				}
25899			};
25900		},
25901		autosave: function()
25902		{
25903			return {
25904				html: false,
25905				enable: function()
25906				{
25907					if (!this.opts.autosave) return;
25908
25909					this.autosave.name = (this.opts.autosaveName) ? this.opts.autosaveName : this.$textarea.attr('name');
25910
25911					if (this.opts.autosaveOnChange) return;
25912					this.autosaveInterval = setInterval(this.autosave.load, this.opts.autosaveInterval * 1000);
25913				},
25914				onChange: function()
25915				{
25916					if (!this.opts.autosaveOnChange) return;
25917					this.autosave.load();
25918				},
25919				load: function()
25920				{
25921					if (!this.opts.autosave) return;
25922
25923					this.autosave.source = this.code.get();
25924
25925					if (this.autosave.html === this.autosave.source) return;
25926
25927					// data
25928					var data = {};
25929					data['name'] = this.autosave.name;
25930					data[this.autosave.name] = this.autosave.source;
25931					data = this.autosave.getHiddenFields(data);
25932
25933					// ajax
25934					var jsxhr = $.ajax({
25935						url: this.opts.autosave,
25936						type: 'post',
25937						data: data
25938					});
25939
25940					jsxhr.done(this.autosave.success);
25941				},
25942				getHiddenFields: function(data)
25943				{
25944					if (this.opts.autosaveFields === false || typeof this.opts.autosaveFields !== 'object')
25945					{
25946						return data;
25947					}
25948
25949					$.each(this.opts.autosaveFields, $.proxy(function(k, v)
25950					{
25951						if (v !== null && v.toString().indexOf('#') === 0) v = $(v).val();
25952						data[k] = v;
25953
25954					}, this));
25955
25956					return data;
25957
25958				},
25959				success: function(data)
25960				{
25961					var json;
25962					try
25963					{
25964						json = $.parseJSON(data);
25965					}
25966					catch(e)
25967					{
25968						//data has already been parsed
25969						json = data;
25970					}
25971
25972					var callbackName = (typeof json.error == 'undefined') ? 'autosave' :  'autosaveError';
25973
25974					this.core.setCallback(callbackName, this.autosave.name, json);
25975					this.autosave.html = this.autosave.source;
25976				},
25977				disable: function()
25978				{
25979					clearInterval(this.autosaveInterval);
25980				}
25981			};
25982		},
25983		block: function()
25984		{
25985			return {
25986				formatting: function(name)
25987				{
25988					this.block.clearStyle = false;
25989					var type, value;
25990
25991					if (typeof this.formatting[name].data != 'undefined') type = 'data';
25992					else if (typeof this.formatting[name].attr != 'undefined') type = 'attr';
25993					else if (typeof this.formatting[name]['class'] != 'undefined') type = 'class';
25994
25995					if (typeof this.formatting[name].clear != 'undefined')
25996					{
25997						this.block.clearStyle = true;
25998					}
25999
26000					if (type) value = this.formatting[name][type];
26001
26002					this.block.format(this.formatting[name].tag, type, value);
26003
26004				},
26005				format: function(tag, type, value)
26006				{
26007					if (tag == 'quote') tag = 'blockquote';
26008
26009					var formatTags = ['p', 'pre', 'blockquote', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
26010					if ($.inArray(tag, formatTags) == -1) return;
26011
26012					this.block.isRemoveInline = (tag == 'pre' || tag.search(/h[1-6]/i) != -1);
26013
26014					// focus
26015					if (!this.utils.browser('msie')) this.$editor.focus();
26016
26017					var html = $.trim(this.$editor.html());
26018					this.block.isEmpty = this.utils.isEmpty(html);
26019
26020					// FF focus
26021					if (this.utils.browser('mozilla') && !this.focus.isFocused())
26022					{
26023						if (this.block.isEmpty)
26024						{
26025							var $first;
26026							if (!this.opts.linebreaks)
26027							{
26028								$first = this.$editor.children().first();
26029								this.caret.setEnd($first);
26030							}
26031						}
26032					}
26033
26034					this.block.blocks = this.selection.getBlocks();
26035
26036					this.block.blocksSize = this.block.blocks.length;
26037					this.block.type = type;
26038					this.block.value = value;
26039
26040					this.buffer.set();
26041					this.selection.save();
26042
26043					this.block.set(tag);
26044
26045					this.selection.restore();
26046					this.code.sync();
26047					this.observe.load();
26048
26049				},
26050				set: function(tag)
26051				{
26052
26053					this.selection.get();
26054					this.block.containerTag = this.range.commonAncestorContainer.tagName;
26055
26056					if (this.range.collapsed)
26057					{
26058						this.block.setCollapsed(tag);
26059					}
26060					else
26061					{
26062						this.block.setMultiple(tag);
26063					}
26064				},
26065				setCollapsed: function(tag)
26066				{
26067					if (this.opts.linebreaks && this.block.isEmpty && tag != 'p')
26068					{
26069						var node = document.createElement(tag);
26070						this.$editor.html(node);
26071						this.caret.setEnd(node);
26072
26073						return;
26074					}
26075
26076					var block = this.block.blocks[0];
26077					if (block === false) return;
26078
26079					if (block.tagName == 'LI')
26080					{
26081						if (tag != 'blockquote') return;
26082
26083						this.block.formatListToBlockquote();
26084						return;
26085					}
26086
26087					var isContainerTable = (this.block.containerTag  == 'TD' || this.block.containerTag  == 'TH');
26088					if (isContainerTable && !this.opts.linebreaks)
26089					{
26090						document.execCommand('formatblock', false, '<' + tag + '>');
26091
26092						block = this.selection.getBlock();
26093						this.block.toggle($(block));
26094
26095					}
26096					else if (block.tagName.toLowerCase() != tag)
26097					{
26098						if (this.opts.linebreaks && tag == 'p')
26099						{
26100							$(block).append('<br>');
26101							this.utils.replaceWithContents(block);
26102						}
26103						else
26104						{
26105							var $formatted = this.utils.replaceToTag(block, tag);
26106
26107							this.block.toggle($formatted);
26108
26109							if (tag != 'p' && tag != 'blockquote') $formatted.find('img').remove();
26110							if (this.block.isRemoveInline) this.utils.removeInlineTags($formatted);
26111							if (tag == 'p' || this.block.headTag) $formatted.find('p').contents().unwrap();
26112
26113							this.block.formatTableWrapping($formatted);
26114						}
26115					}
26116					else if (tag == 'blockquote' && block.tagName.toLowerCase() == tag)
26117					{
26118						// blockquote off
26119						if (this.opts.linebreaks)
26120						{
26121							$(block).append('<br>');
26122							this.utils.replaceWithContents(block);
26123						}
26124						else
26125						{
26126							var $el = this.utils.replaceToTag(block, 'p');
26127							this.block.toggle($el);
26128						}
26129					}
26130					else if (block.tagName.toLowerCase() == tag)
26131					{
26132						this.block.toggle($(block));
26133					}
26134
26135
26136					if (typeof this.block.type == 'undefined' && typeof this.block.value == 'undefined')
26137					{
26138						$(block).removeAttr('class').removeAttr('style');
26139					}
26140				},
26141				setMultiple: function(tag)
26142				{
26143					var block = this.block.blocks[0];
26144
26145					var isContainerTable = (this.block.containerTag  == 'TD' || this.block.containerTag  == 'TH');
26146
26147					if (block !== false && this.block.blocksSize === 1)
26148					{
26149						if (block.tagName.toLowerCase() == tag &&  tag == 'blockquote')
26150						{
26151							// blockquote off
26152							if (this.opts.linebreaks)
26153							{
26154								$(block).append('<br>');
26155								this.utils.replaceWithContents(block);
26156							}
26157							else
26158							{
26159								var $el = this.utils.replaceToTag(block, 'p');
26160								this.block.toggle($el);
26161							}
26162						}
26163						else if (block.tagName == 'LI')
26164						{
26165							if (tag != 'blockquote') return;
26166
26167							this.block.formatListToBlockquote();
26168						}
26169						else if (this.block.containerTag == 'BLOCKQUOTE')
26170						{
26171							this.block.formatBlockquote(tag);
26172						}
26173						else if (this.opts.linebreaks && ((isContainerTable) || (this.range.commonAncestorContainer != block)))
26174						{
26175							this.block.formatWrap(tag);
26176						}
26177						else
26178						{
26179							if (this.opts.linebreaks && tag == 'p')
26180							{
26181								$(block).prepend('<br>').append('<br>');
26182								this.utils.replaceWithContents(block);
26183							}
26184							else if (block.tagName === 'TD')
26185							{
26186								this.block.formatWrap(tag);
26187							}
26188							else
26189							{
26190								var $formatted = this.utils.replaceToTag(block, tag);
26191
26192								this.block.toggle($formatted);
26193
26194								if (this.block.isRemoveInline) this.utils.removeInlineTags($formatted);
26195								if (tag == 'p' || this.block.headTag) $formatted.find('p').contents().unwrap();
26196							}
26197						}
26198					}
26199					else
26200					{
26201						if (this.opts.linebreaks || tag != 'p')
26202						{
26203							if (tag == 'blockquote')
26204							{
26205								var count = 0;
26206								for (var i = 0; i < this.block.blocksSize; i++)
26207								{
26208									if (this.block.blocks[i].tagName == 'BLOCKQUOTE') count++;
26209								}
26210
26211								// only blockquote selected
26212								if (count == this.block.blocksSize)
26213								{
26214									$.each(this.block.blocks, $.proxy(function(i,s)
26215									{
26216										var $formatted = false;
26217										if (this.opts.linebreaks)
26218										{
26219											$(s).prepend('<br>').append('<br>');
26220											$formatted = this.utils.replaceWithContents(s);
26221										}
26222										else
26223										{
26224											$formatted = this.utils.replaceToTag(s, 'p');
26225										}
26226
26227										if ($formatted && typeof this.block.type == 'undefined' && typeof this.block.value == 'undefined')
26228										{
26229											$formatted.removeAttr('class').removeAttr('style');
26230										}
26231
26232									}, this));
26233
26234									return;
26235								}
26236
26237							}
26238
26239							this.block.formatWrap(tag);
26240						}
26241						else
26242						{
26243							var classSize = 0;
26244							var toggleType = false;
26245							if (this.block.type == 'class')
26246							{
26247								toggleType = 'toggle';
26248								classSize = $(this.block.blocks).filter('.' + this.block.value).length;
26249
26250								if (this.block.blocksSize == classSize) toggleType = 'toggle';
26251								else if (this.block.blocksSize > classSize) toggleType = 'set';
26252								else if (classSize === 0) toggleType = 'set';
26253
26254							}
26255
26256							var exceptTags = ['ul', 'ol', 'li', 'td', 'th', 'dl', 'dt', 'dd'];
26257							$.each(this.block.blocks, $.proxy(function(i,s)
26258							{
26259								if ($.inArray(s.tagName.toLowerCase(), exceptTags) != -1) return;
26260
26261								var $formatted = this.utils.replaceToTag(s, tag);
26262
26263								if (toggleType)
26264								{
26265									if (toggleType == 'toggle') this.block.toggle($formatted);
26266									else if (toggleType == 'remove') this.block.remove($formatted);
26267									else if (toggleType == 'set') this.block.setForce($formatted);
26268								}
26269								else this.block.toggle($formatted);
26270
26271								if (tag != 'p' && tag != 'blockquote') $formatted.find('img').remove();
26272								if (this.block.isRemoveInline) this.utils.removeInlineTags($formatted);
26273								if (tag == 'p' || this.block.headTag) $formatted.find('p').contents().unwrap();
26274
26275								if (typeof this.block.type == 'undefined' && typeof this.block.value == 'undefined')
26276								{
26277									$formatted.removeAttr('class').removeAttr('style');
26278								}
26279
26280
26281							}, this));
26282						}
26283					}
26284				},
26285				setForce: function($el)
26286				{
26287					// remove style and class if the specified setting
26288					if (this.block.clearStyle)
26289					{
26290						$el.removeAttr('class').removeAttr('style');
26291					}
26292
26293					if (this.block.type == 'class')
26294					{
26295						$el.addClass(this.block.value);
26296						return;
26297					}
26298					else if (this.block.type == 'attr' || this.block.type == 'data')
26299					{
26300						$el.attr(this.block.value.name, this.block.value.value);
26301						return;
26302					}
26303				},
26304				toggle: function($el)
26305				{
26306					// remove style and class if the specified setting
26307					if (this.block.clearStyle)
26308					{
26309						$el.removeAttr('class').removeAttr('style');
26310					}
26311
26312					if (this.block.type == 'class')
26313					{
26314						$el.toggleClass(this.block.value);
26315						return;
26316					}
26317					else if (this.block.type == 'attr' || this.block.type == 'data')
26318					{
26319						if ($el.attr(this.block.value.name) == this.block.value.value)
26320						{
26321							$el.removeAttr(this.block.value.name);
26322						}
26323						else
26324						{
26325							$el.attr(this.block.value.name, this.block.value.value);
26326						}
26327
26328						return;
26329					}
26330					else
26331					{
26332						$el.removeAttr('style class');
26333						return;
26334					}
26335				},
26336				remove: function($el)
26337				{
26338					$el.removeClass(this.block.value);
26339				},
26340				formatListToBlockquote: function()
26341				{
26342					var block = $(this.block.blocks[0]).closest('ul, ol', this.$editor[0]);
26343
26344					$(block).find('ul, ol').contents().unwrap();
26345					$(block).find('li').append($('<br>')).contents().unwrap();
26346
26347					var $el = this.utils.replaceToTag(block, 'blockquote');
26348					this.block.toggle($el);
26349				},
26350				formatBlockquote: function(tag)
26351				{
26352					document.execCommand('outdent');
26353					document.execCommand('formatblock', false, tag);
26354
26355					this.clean.clearUnverified();
26356					this.$editor.find('p:empty').remove();
26357
26358					var formatted = this.selection.getBlock();
26359
26360					if (tag != 'p')
26361					{
26362						$(formatted).find('img').remove();
26363					}
26364
26365					if (!this.opts.linebreaks)
26366					{
26367						this.block.toggle($(formatted));
26368					}
26369
26370					this.$editor.find('ul, ol, tr, blockquote, p').each($.proxy(this.utils.removeEmpty, this));
26371
26372					if (this.opts.linebreaks && tag == 'p')
26373					{
26374						this.utils.replaceWithContents(formatted);
26375					}
26376
26377				},
26378				formatWrap: function(tag)
26379				{
26380					if (this.block.containerTag == 'UL' || this.block.containerTag == 'OL')
26381					{
26382						if (tag == 'blockquote')
26383						{
26384							this.block.formatListToBlockquote();
26385						}
26386						else
26387						{
26388							return;
26389						}
26390					}
26391
26392					var formatted = this.selection.wrap(tag);
26393					if (formatted === false) return;
26394
26395					var $formatted = $(formatted);
26396
26397					this.block.formatTableWrapping($formatted);
26398
26399					var $elements = $formatted.find(this.opts.blockLevelElements.join(',') + ', td, table, thead, tbody, tfoot, th, tr');
26400
26401					$elements.contents().unwrap();
26402
26403					if (tag != 'p' && tag != 'blockquote') $formatted.find('img').remove();
26404
26405					$.each(this.block.blocks, $.proxy(this.utils.removeEmpty, this));
26406
26407					$formatted.append(this.selection.getMarker(2));
26408
26409					if (!this.opts.linebreaks)
26410					{
26411						this.block.toggle($formatted);
26412					}
26413
26414					this.$editor.find('ul, ol, tr, blockquote, p').each($.proxy(this.utils.removeEmpty, this));
26415					$formatted.find('blockquote:empty').remove();
26416
26417					if (this.block.isRemoveInline)
26418					{
26419						this.utils.removeInlineTags($formatted);
26420					}
26421
26422					if (this.opts.linebreaks && tag == 'p')
26423					{
26424						this.utils.replaceWithContents($formatted);
26425					}
26426
26427					if (this.opts.linebreaks)
26428					{
26429						var $next = $formatted.next().next();
26430						if ($next.size() != 0 && $next[0].tagName === 'BR')
26431						{
26432							$next.remove();
26433						}
26434					}
26435
26436
26437
26438				},
26439				formatTableWrapping: function($formatted)
26440				{
26441					if ($formatted.closest('table', this.$editor[0]).length === 0) return;
26442
26443					if ($formatted.closest('tr', this.$editor[0]).length === 0) $formatted.wrap('<tr>');
26444					if ($formatted.closest('td', this.$editor[0]).length === 0 && $formatted.closest('th').length === 0)
26445					{
26446						$formatted.wrap('<td>');
26447					}
26448				},
26449				removeData: function(name, value)
26450				{
26451					var blocks = this.selection.getBlocks();
26452					$(blocks).removeAttr('data-' + name);
26453
26454					this.code.sync();
26455				},
26456				setData: function(name, value)
26457				{
26458					var blocks = this.selection.getBlocks();
26459					$(blocks).attr('data-' + name, value);
26460
26461					this.code.sync();
26462				},
26463				toggleData: function(name, value)
26464				{
26465					var blocks = this.selection.getBlocks();
26466					$.each(blocks, function()
26467					{
26468						if ($(this).attr('data-' + name))
26469						{
26470							$(this).removeAttr('data-' + name);
26471						}
26472						else
26473						{
26474							$(this).attr('data-' + name, value);
26475						}
26476					});
26477				},
26478				removeAttr: function(attr, value)
26479				{
26480					var blocks = this.selection.getBlocks();
26481					$(blocks).removeAttr(attr);
26482
26483					this.code.sync();
26484				},
26485				setAttr: function(attr, value)
26486				{
26487					var blocks = this.selection.getBlocks();
26488					$(blocks).attr(attr, value);
26489
26490					this.code.sync();
26491				},
26492				toggleAttr: function(attr, value)
26493				{
26494					var blocks = this.selection.getBlocks();
26495					$.each(blocks, function()
26496					{
26497						if ($(this).attr(name))
26498						{
26499							$(this).removeAttr(name);
26500						}
26501						else
26502						{
26503							$(this).attr(name, value);
26504						}
26505					});
26506				},
26507				removeClass: function(className)
26508				{
26509					var blocks = this.selection.getBlocks();
26510					$(blocks).removeClass(className);
26511
26512					this.utils.removeEmptyAttr(blocks, 'class');
26513
26514					this.code.sync();
26515				},
26516				setClass: function(className)
26517				{
26518					var blocks = this.selection.getBlocks();
26519					$(blocks).addClass(className);
26520
26521					this.code.sync();
26522				},
26523				toggleClass: function(className)
26524				{
26525					var blocks = this.selection.getBlocks();
26526					$(blocks).toggleClass(className);
26527
26528					this.code.sync();
26529				}
26530			};
26531		},
26532		buffer: function()
26533		{
26534			return {
26535				set: function(type)
26536				{
26537					if (typeof type == 'undefined' || type == 'undo')
26538					{
26539						this.buffer.setUndo();
26540					}
26541					else
26542					{
26543						this.buffer.setRedo();
26544					}
26545				},
26546				setUndo: function()
26547				{
26548					this.selection.save();
26549					this.opts.buffer.push(this.$editor.html());
26550					this.selection.restore();
26551				},
26552				setRedo: function()
26553				{
26554					this.selection.save();
26555					this.opts.rebuffer.push(this.$editor.html());
26556					this.selection.restore();
26557				},
26558				getUndo: function()
26559				{
26560					this.$editor.html(this.opts.buffer.pop());
26561				},
26562				getRedo: function()
26563				{
26564					this.$editor.html(this.opts.rebuffer.pop());
26565				},
26566				add: function()
26567				{
26568					this.opts.buffer.push(this.$editor.html());
26569				},
26570				undo: function()
26571				{
26572					if (this.opts.buffer.length === 0) return;
26573
26574					this.buffer.set('redo');
26575					this.buffer.getUndo();
26576
26577					this.selection.restore();
26578
26579					setTimeout($.proxy(this.observe.load, this), 50);
26580				},
26581				redo: function()
26582				{
26583					if (this.opts.rebuffer.length === 0) return;
26584
26585					this.buffer.set('undo');
26586					this.buffer.getRedo();
26587
26588					this.selection.restore();
26589
26590					setTimeout($.proxy(this.observe.load, this), 50);
26591				}
26592			};
26593		},
26594		build: function()
26595		{
26596			return {
26597				focused: false,
26598				blured: true,
26599				run: function()
26600				{
26601					this.build.createContainerBox();
26602					this.build.loadContent();
26603					this.build.loadEditor();
26604					this.build.enableEditor();
26605					this.build.setCodeAndCall();
26606				},
26607				isTextarea: function()
26608				{
26609					return (this.$element[0].tagName === 'TEXTAREA');
26610				},
26611				createContainerBox: function()
26612				{
26613					this.$box = $('<div class="redactor-box" role="application" />');
26614				},
26615				createTextarea: function()
26616				{
26617					this.$textarea = $('<textarea />').attr('name', this.build.getTextareaName());
26618				},
26619				getTextareaName: function()
26620				{
26621					return ((typeof(name) == 'undefined')) ? 'content-' + this.uuid : this.$element.attr('id');
26622				},
26623				loadContent: function()
26624				{
26625					var func = (this.build.isTextarea()) ? 'val' : 'html';
26626					this.content = $.trim(this.$element[func]());
26627				},
26628				enableEditor: function()
26629				{
26630					this.$editor.attr({ 'contenteditable': true, 'dir': this.opts.direction });
26631				},
26632				loadEditor: function()
26633				{
26634					var func = (this.build.isTextarea()) ? 'fromTextarea' : 'fromElement';
26635					this.build[func]();
26636				},
26637				fromTextarea: function()
26638				{
26639					this.$editor = $('<div />');
26640					this.$textarea = this.$element;
26641					this.$box.insertAfter(this.$element).append(this.$editor).append(this.$element);
26642					this.$editor.addClass('redactor-editor');
26643
26644					this.$element.hide();
26645				},
26646				fromElement: function()
26647				{
26648					this.$editor = this.$element;
26649					this.build.createTextarea();
26650					this.$box.insertAfter(this.$editor).append(this.$editor).append(this.$textarea);
26651					this.$editor.addClass('redactor-editor');
26652
26653					this.$textarea.hide();
26654				},
26655				setCodeAndCall: function()
26656				{
26657					// set code
26658					this.code.set(this.content);
26659
26660					this.build.setOptions();
26661					this.build.callEditor();
26662
26663					// code mode
26664					if (this.opts.visual) return;
26665					setTimeout($.proxy(this.code.showCode, this), 200);
26666				},
26667				callEditor: function()
26668				{
26669					this.build.disableMozillaEditing();
26670					this.build.disableIeLinks();
26671					this.build.setEvents();
26672					this.build.setHelpers();
26673
26674					// load toolbar
26675					if (this.opts.toolbar)
26676					{
26677						this.opts.toolbar = this.toolbar.init();
26678						this.toolbar.build();
26679					}
26680
26681					// modal templates init
26682					this.modal.loadTemplates();
26683
26684					// plugins
26685					this.build.plugins();
26686
26687					// observers
26688					setTimeout($.proxy(this.observe.load, this), 4);
26689
26690					// init callback
26691					this.core.setCallback('init');
26692				},
26693				setOptions: function()
26694				{
26695					// textarea direction
26696					$(this.$textarea).attr('dir', this.opts.direction);
26697
26698					if (this.opts.linebreaks) this.$editor.addClass('redactor-linebreaks');
26699
26700					if (this.opts.tabindex) this.$editor.attr('tabindex', this.opts.tabindex);
26701
26702					if (this.opts.minHeight) this.$editor.css('minHeight', this.opts.minHeight);
26703					if (this.opts.maxHeight) this.$editor.css('maxHeight', this.opts.maxHeight);
26704
26705				},
26706				setEventDropUpload: function(e)
26707				{
26708					e.preventDefault();
26709
26710					if (!this.opts.dragImageUpload && !this.opts.dragFileUpload) return;
26711					if (this.opts.imageUpload === null && this.opts.fileUpload === null) return;
26712
26713					var files = e.dataTransfer.files;
26714					this.upload.directUpload(files[0], e);
26715				},
26716				setEventDrop: function(e)
26717				{
26718					this.code.sync();
26719					setTimeout(this.clean.clearUnverified, 1);
26720					this.core.setCallback('drop', e);
26721				},
26722				setEvents: function()
26723				{
26724					// drop
26725					this.$editor.on('dragover.redactor dragenter.redactor', function(e)
26726					{
26727						e.preventDefault();
26728						e.stopPropagation();
26729				    });
26730
26731					this.$editor.on('drop.redactor', $.proxy(function(e)
26732					{
26733						e = e.originalEvent || e;
26734
26735						if (window.FormData === undefined || !e.dataTransfer) return true;
26736
26737						if (e.dataTransfer.files.length === 0)
26738						{
26739							return this.build.setEventDrop(e);
26740						}
26741						else
26742						{
26743							this.build.setEventDropUpload(e);
26744						}
26745
26746						setTimeout(this.clean.clearUnverified, 1);
26747						this.core.setCallback('drop', e);
26748
26749					}, this));
26750
26751
26752					// click
26753					this.$editor.on('click.redactor', $.proxy(function(e)
26754					{
26755						var event = this.core.getEvent();
26756						var type = (event == 'click' || event == 'arrow') ? false : 'click';
26757
26758						this.core.addEvent(type);
26759						this.utils.disableSelectAll();
26760						this.core.setCallback('click', e);
26761
26762					}, this));
26763
26764					// paste
26765					this.$editor.on('paste.redactor', $.proxy(this.paste.init, this));
26766
26767					// cut
26768					this.$editor.on('cut.redactor', $.proxy(this.code.sync, this));
26769
26770					// keydown
26771					this.$editor.on('keydown.redactor', $.proxy(this.keydown.init, this));
26772
26773					// keyup
26774					this.$editor.on('keyup.redactor', $.proxy(this.keyup.init, this));
26775
26776					// textarea keydown
26777					if ($.isFunction(this.opts.codeKeydownCallback))
26778					{
26779						this.$textarea.on('keydown.redactor-textarea', $.proxy(this.opts.codeKeydownCallback, this));
26780					}
26781
26782					// textarea keyup
26783					if ($.isFunction(this.opts.codeKeyupCallback))
26784					{
26785						this.$textarea.on('keyup.redactor-textarea', $.proxy(this.opts.codeKeyupCallback, this));
26786					}
26787
26788					// focus
26789					this.$editor.on('focus.redactor', $.proxy(function(e)
26790					{
26791						if ($.isFunction(this.opts.focusCallback))
26792						{
26793							this.core.setCallback('focus', e);
26794						}
26795
26796						this.build.focused = true;
26797						this.build.blured = false;
26798
26799						if (this.selection.getCurrent() === false)
26800						{
26801							this.selection.get();
26802							this.range.setStart(this.$editor[0], 0);
26803							this.range.setEnd(this.$editor[0], 0);
26804							this.selection.addRange();
26805						}
26806
26807
26808					}, this));
26809
26810
26811					// blur
26812					$(document).on('mousedown.redactor-blur.' + this.uuid, $.proxy(function(e)
26813					{
26814						if (this.start) return;
26815						if (this.rtePaste) return;
26816
26817						if ($(e.target).closest('.redactor-editor, .redactor-toolbar, .redactor-dropdown').size() !== 0)
26818						{
26819							return;
26820						}
26821
26822						this.utils.disableSelectAll();
26823						if (!this.build.blured && $.isFunction(this.opts.blurCallback))
26824						{
26825							this.core.setCallback('blur', e);
26826						}
26827
26828						this.build.focused = false;
26829						this.build.blured = true;
26830
26831					}, this));
26832
26833				},
26834				setHelpers: function()
26835				{
26836					// linkify
26837					if (this.linkify.isEnabled())
26838					{
26839						this.linkify.format();
26840					}
26841
26842					// placeholder
26843					this.placeholder.enable();
26844
26845					// focus
26846					if (this.opts.focus) setTimeout(this.focus.setStart, 100);
26847					if (this.opts.focusEnd) setTimeout(this.focus.setEnd, 100);
26848
26849				},
26850				plugins: function()
26851				{
26852					if (!this.opts.plugins) return;
26853
26854					$.each(this.opts.plugins, $.proxy(function(i, s)
26855					{
26856						var func = (typeof RedactorPlugins !== 'undefined' && typeof RedactorPlugins[s] !== 'undefined') ? RedactorPlugins : Redactor.fn;
26857
26858						if (!$.isFunction(func[s]))
26859						{
26860							return;
26861						}
26862
26863						this[s] = func[s]();
26864
26865						// get methods
26866						var methods = this.getModuleMethods(this[s]);
26867						var len = methods.length;
26868
26869						// bind methods
26870						for (var z = 0; z < len; z++)
26871						{
26872							this[s][methods[z]] = this[s][methods[z]].bind(this);
26873						}
26874
26875						if ($.isFunction(this[s].init))
26876						{
26877							this[s].init();
26878						}
26879
26880
26881					}, this));
26882
26883				},
26884				disableMozillaEditing: function()
26885				{
26886					if (!this.utils.browser('mozilla')) return;
26887
26888					// FF fix
26889					try {
26890						document.execCommand('enableObjectResizing', false, false);
26891						document.execCommand('enableInlineTableEditing', false, false);
26892					} catch (e) {}
26893				},
26894				disableIeLinks: function()
26895				{
26896					if (!this.utils.browser('msie')) return;
26897
26898					// IE prevent converting links
26899					document.execCommand("AutoUrlDetect", false, false);
26900				}
26901			};
26902		},
26903		button: function()
26904		{
26905			return {
26906				build: function(btnName, btnObject)
26907				{
26908					var $button = $('<a href="#" class="re-icon re-' + btnName + '" rel="' + btnName + '" />').attr({'role': 'button', 'aria-label': btnObject.title, 'tabindex': '-1'});
26909
26910					// click
26911					if (btnObject.func || btnObject.command || btnObject.dropdown)
26912					{
26913						this.button.setEvent($button, btnName, btnObject);
26914					}
26915
26916					// dropdown
26917					if (btnObject.dropdown)
26918					{
26919						$button.addClass('redactor-toolbar-link-dropdown').attr('aria-haspopup', true);
26920
26921						var $dropdown = $('<div class="redactor-dropdown redactor-dropdown-' + this.uuid + ' redactor-dropdown-box-' + btnName + '" style="display: none;">');
26922						$button.data('dropdown', $dropdown);
26923						this.dropdown.build(btnName, $dropdown, btnObject.dropdown);
26924					}
26925
26926					// tooltip
26927					if (this.utils.isDesktop())
26928					{
26929						this.button.createTooltip($button, btnName, btnObject.title);
26930					}
26931
26932					return $button;
26933				},
26934				setEvent: function($button, btnName, btnObject)
26935				{
26936					$button.on('touchstart click', $.proxy(function(e)
26937					{
26938						if ($button.hasClass('redactor-button-disabled')) return false;
26939
26940						var type = 'func';
26941						var callback = btnObject.func;
26942
26943						if (btnObject.command)
26944						{
26945							type = 'command';
26946							callback = btnObject.command;
26947						}
26948						else if (btnObject.dropdown)
26949						{
26950							type = 'dropdown';
26951							callback = false;
26952						}
26953
26954						this.button.onClick(e, btnName, type, callback);
26955
26956					}, this));
26957				},
26958				createTooltip: function($button, name, title)
26959				{
26960					var $tooltip = $('<span>').addClass('redactor-toolbar-tooltip redactor-toolbar-tooltip-' + this.uuid + ' redactor-toolbar-tooltip-' + name).hide().html(title);
26961					$tooltip.appendTo('body');
26962
26963					$button.on('mouseover', function()
26964					{
26965						if ($(this).hasClass('redactor-button-disabled'))
26966						{
26967							return;
26968						}
26969
26970						var pos = $button.offset();
26971
26972						$tooltip.css({
26973							top: (pos.top + $button.innerHeight()) + 'px',
26974							left: (pos.left + $button.innerWidth()/2 - $tooltip.innerWidth()/2) + 'px'
26975						});
26976						$tooltip.show();
26977
26978					});
26979
26980					$button.on('mouseout', function()
26981					{
26982						$tooltip.hide();
26983					});
26984
26985				},
26986				onClick: function(e, btnName, type, callback)
26987				{
26988					this.button.caretOffset = this.caret.getOffset();
26989
26990					e.preventDefault();
26991
26992					$(document).find('.redactor-toolbar-tooltip').hide();
26993
26994					if (this.utils.browser('msie')) e.returnValue = false;
26995
26996					if (type == 'command') this.inline.format(callback);
26997					else if (type == 'dropdown') this.dropdown.show(e, btnName);
26998					else this.button.onClickCallback(e, callback, btnName);
26999				},
27000				onClickCallback: function(e, callback, btnName)
27001				{
27002					var func;
27003
27004					if ($.isFunction(callback)) callback.call(this, btnName);
27005					else if (callback.search(/\./) != '-1')
27006					{
27007						func = callback.split('.');
27008						if (typeof this[func[0]] == 'undefined') return;
27009
27010						this[func[0]][func[1]](btnName);
27011					}
27012					else this[callback](btnName);
27013
27014					this.observe.buttons(e, btnName);
27015				},
27016				get: function(key)
27017				{
27018					return this.$toolbar.find('a.re-' + key);
27019				},
27020				setActive: function(key)
27021				{
27022					this.button.get(key).addClass('redactor-act');
27023				},
27024				setInactive: function(key)
27025				{
27026					this.button.get(key).removeClass('redactor-act');
27027				},
27028				setInactiveAll: function(key)
27029				{
27030					if (typeof key === 'undefined')
27031					{
27032						this.$toolbar.find('a.re-icon').removeClass('redactor-act');
27033					}
27034					else
27035					{
27036						this.$toolbar.find('a.re-icon').not('.re-' + key).removeClass('redactor-act');
27037					}
27038				},
27039				setActiveInVisual: function()
27040				{
27041					this.$toolbar.find('a.re-icon').not('a.re-html, a.re-fullscreen').removeClass('redactor-button-disabled');
27042				},
27043				setInactiveInCode: function()
27044				{
27045					this.$toolbar.find('a.re-icon').not('a.re-html, a.re-fullscreen').addClass('redactor-button-disabled');
27046				},
27047				changeIcon: function(key, classname)
27048				{
27049					this.button.get(key).addClass('re-' + classname);
27050				},
27051				removeIcon: function(key, classname)
27052				{
27053					this.button.get(key).removeClass('re-' + classname);
27054				},
27055				setAwesome: function(key, name)
27056				{
27057					var $button = this.button.get(key);
27058					$button.removeClass('redactor-btn-image').addClass('fa-redactor-btn');
27059					$button.html('<i class="fa ' + name + '"></i>');
27060				},
27061				addCallback: function($btn, callback)
27062				{
27063					if ($btn == "buffer") return;
27064
27065					var type = (callback == 'dropdown') ? 'dropdown' : 'func';
27066					var key = $btn.attr('rel');
27067					$btn.on('touchstart click', $.proxy(function(e)
27068					{
27069						if ($btn.hasClass('redactor-button-disabled')) return false;
27070						this.button.onClick(e, key, type, callback);
27071
27072					}, this));
27073				},
27074				addDropdown: function($btn, dropdown)
27075				{
27076					$btn.addClass('redactor-toolbar-link-dropdown').attr('aria-haspopup', true);
27077
27078					var key = $btn.attr('rel');
27079					this.button.addCallback($btn, 'dropdown');
27080
27081					var $dropdown = $('<div class="redactor-dropdown redactor-dropdown-' + this.uuid + ' redactor-dropdown-box-' + key + '" style="display: none;">');
27082					$btn.data('dropdown', $dropdown);
27083
27084					// build dropdown
27085					if (dropdown) this.dropdown.build(key, $dropdown, dropdown);
27086
27087					return $dropdown;
27088				},
27089				add: function(key, title)
27090				{
27091					if (!this.opts.toolbar) return;
27092
27093					if (this.button.isMobileUndoRedo(key)) return "buffer";
27094
27095					var btn = this.button.build(key, { title: title });
27096					btn.addClass('redactor-btn-image');
27097
27098					this.$toolbar.append($('<li>').append(btn));
27099
27100					return btn;
27101				},
27102				addFirst: function(key, title)
27103				{
27104					if (!this.opts.toolbar) return;
27105
27106					if (this.button.isMobileUndoRedo(key)) return "buffer";
27107
27108					var btn = this.button.build(key, { title: title });
27109					btn.addClass('redactor-btn-image');
27110					this.$toolbar.prepend($('<li>').append(btn));
27111
27112					return btn;
27113				},
27114				addAfter: function(afterkey, key, title)
27115				{
27116					if (!this.opts.toolbar) return;
27117
27118					if (this.button.isMobileUndoRedo(key)) return "buffer";
27119
27120					var btn = this.button.build(key, { title: title });
27121					btn.addClass('redactor-btn-image');
27122					var $btn = this.button.get(afterkey);
27123
27124					if ($btn.length !== 0) $btn.parent().after($('<li>').append(btn));
27125					else this.$toolbar.append($('<li>').append(btn));
27126
27127					return btn;
27128				},
27129				addBefore: function(beforekey, key, title)
27130				{
27131					if (!this.opts.toolbar) return;
27132
27133					if (this.button.isMobileUndoRedo(key)) return "buffer";
27134
27135					var btn = this.button.build(key, { title: title });
27136					btn.addClass('redactor-btn-image');
27137					var $btn = this.button.get(beforekey);
27138
27139					if ($btn.length !== 0) $btn.parent().before($('<li>').append(btn));
27140					else this.$toolbar.append($('<li>').append(btn));
27141
27142					return btn;
27143				},
27144				remove: function(key)
27145				{
27146					this.button.get(key).remove();
27147				},
27148				isMobileUndoRedo: function(key)
27149				{
27150					return (key == "undo" || key == "redo") && !this.utils.isDesktop();
27151				}
27152			};
27153		},
27154		caret: function()
27155		{
27156			return {
27157				setStart: function(node)
27158				{
27159					// inline tag
27160					if (!this.utils.isBlock(node))
27161					{
27162						var space = this.utils.createSpaceElement();
27163
27164						$(node).prepend(space);
27165						this.caret.setEnd(space);
27166					}
27167					else
27168					{
27169						this.caret.set(node, 0, node, 0);
27170					}
27171				},
27172				setEnd: function(node)
27173				{
27174					node = node[0] || node;
27175					if (node.lastChild.nodeType == 1)
27176					{
27177						return this.caret.setAfter(node.lastChild);
27178					}
27179
27180					this.caret.set(node, 1, node, 1);
27181
27182				},
27183				set: function(orgn, orgo, focn, foco)
27184				{
27185					// focus
27186					// disabled in 10.0.7
27187					// if (!this.utils.browser('msie')) this.$editor.focus();
27188
27189					orgn = orgn[0] || orgn;
27190					focn = focn[0] || focn;
27191
27192					if (this.utils.isBlockTag(orgn.tagName) && orgn.innerHTML === '')
27193					{
27194						orgn.innerHTML = this.opts.invisibleSpace;
27195					}
27196
27197					if (orgn.tagName == 'BR' && this.opts.linebreaks === false)
27198					{
27199						var parent = $(this.opts.emptyHtml)[0];
27200						$(orgn).replaceWith(parent);
27201						orgn = parent;
27202						focn = orgn;
27203					}
27204
27205					this.selection.get();
27206
27207					try
27208					{
27209						this.range.setStart(orgn, orgo);
27210						this.range.setEnd(focn, foco);
27211					}
27212					catch (e) {}
27213
27214					this.selection.addRange();
27215				},
27216				setAfter: function(node)
27217				{
27218					try
27219					{
27220						var tag = $(node)[0].tagName;
27221
27222						// inline tag
27223						if (tag != 'BR' && !this.utils.isBlock(node))
27224						{
27225							var space = this.utils.createSpaceElement();
27226
27227							$(node).after(space);
27228							this.caret.setEnd(space);
27229						}
27230						else
27231						{
27232							if (tag != 'BR' && this.utils.browser('msie'))
27233							{
27234								this.caret.setStart($(node).next());
27235							}
27236							else
27237							{
27238								this.caret.setAfterOrBefore(node, 'after');
27239							}
27240						}
27241					}
27242					catch (e)
27243					{
27244						var space = this.utils.createSpaceElement();
27245						$(node).after(space);
27246						this.caret.setEnd(space);
27247					}
27248				},
27249				setBefore: function(node)
27250				{
27251					// block tag
27252					if (this.utils.isBlock(node))
27253					{
27254						this.caret.setEnd($(node).prev());
27255					}
27256					else
27257					{
27258						this.caret.setAfterOrBefore(node, 'before');
27259					}
27260				},
27261				setAfterOrBefore: function(node, type)
27262				{
27263					// focus
27264					if (!this.utils.browser('msie')) this.$editor.focus();
27265
27266					node = node[0] || node;
27267
27268					this.selection.get();
27269
27270					if (type == 'after')
27271					{
27272						try {
27273
27274							this.range.setStartAfter(node);
27275							this.range.setEndAfter(node);
27276						}
27277						catch (e) {}
27278					}
27279					else
27280					{
27281						try {
27282							this.range.setStartBefore(node);
27283							this.range.setEndBefore(node);
27284						}
27285						catch (e) {}
27286					}
27287
27288
27289					this.range.collapse(false);
27290					this.selection.addRange();
27291				},
27292				getOffsetOfElement: function(node)
27293				{
27294					node = node[0] || node;
27295
27296					this.selection.get();
27297
27298					var cloned = this.range.cloneRange();
27299					cloned.selectNodeContents(node);
27300					cloned.setEnd(this.range.endContainer, this.range.endOffset);
27301
27302					return $.trim(cloned.toString()).length;
27303				},
27304				getOffset: function()
27305				{
27306					var offset = 0;
27307				    var sel = window.getSelection();
27308
27309				    if (sel.rangeCount > 0)
27310				    {
27311				        var range = window.getSelection().getRangeAt(0);
27312				        var caretRange = range.cloneRange();
27313				        caretRange.selectNodeContents(this.$editor[0]);
27314				        caretRange.setEnd(range.endContainer, range.endOffset);
27315				        offset = caretRange.toString().length;
27316				    }
27317
27318					return offset;
27319				},
27320				setOffset: function(start, end)
27321				{
27322					if (typeof end == 'undefined') end = start;
27323					if (!this.focus.isFocused()) this.focus.setStart();
27324
27325					var sel = this.selection.get();
27326					var node, offset = 0;
27327					var walker = document.createTreeWalker(this.$editor[0], NodeFilter.SHOW_TEXT, null, null);
27328
27329					while (node = walker.nextNode())
27330					{
27331						offset += node.nodeValue.length;
27332						if (offset > start)
27333						{
27334							this.range.setStart(node, node.nodeValue.length + start - offset);
27335							start = Infinity;
27336						}
27337
27338						if (offset >= end)
27339						{
27340							this.range.setEnd(node, node.nodeValue.length + end - offset);
27341							break;
27342						}
27343					}
27344
27345					this.range.collapse(false);
27346					this.selection.addRange();
27347				},
27348				// deprecated
27349				setToPoint: function(start, end)
27350				{
27351					this.caret.setOffset(start, end);
27352				},
27353				getCoords: function()
27354				{
27355					return this.caret.getOffset();
27356				}
27357			};
27358		},
27359		clean: function()
27360		{
27361			return {
27362				onSet: function(html)
27363				{
27364					html = this.clean.savePreCode(html);
27365
27366					// convert script tag
27367					html = html.replace(/<script(.*?[^>]?)>([\w\W]*?)<\/script>/gi, '<pre class="redactor-script-tag" style="display: none;" $1>$2</pre>');
27368
27369					// replace dollar sign to entity
27370					html = html.replace(/\$/g, '&#36;');
27371
27372					// replace special characters in links
27373					html = html.replace(/<a href="(.*?[^>]?)®(.*?[^>]?)">/gi, '<a href="$1&reg$2">');
27374
27375					if (this.opts.replaceDivs && !this.opts.linebreaks) html = this.clean.replaceDivs(html);
27376					if (this.opts.linebreaks)  html = this.clean.replaceParagraphsToBr(html);
27377
27378					// save form tag
27379					html = this.clean.saveFormTags(html);
27380
27381					// convert font tag to span
27382					var $div = $('<div>');
27383					$div.html(html);
27384					var fonts = $div.find('font[style]');
27385					if (fonts.length !== 0)
27386					{
27387						fonts.replaceWith(function()
27388						{
27389							var $el = $(this);
27390							var $span = $('<span>').attr('style', $el.attr('style'));
27391							return $span.append($el.contents());
27392						});
27393
27394						html = $div.html();
27395					}
27396
27397					$div.remove();
27398
27399					// remove font tag
27400					html = html.replace(/<font(.*?)>/gi, '');
27401					html = html.replace(/<\/font>/gi, '');
27402
27403					// tidy html
27404					html = this.tidy.load(html);
27405
27406					// paragraphize
27407					if (this.opts.paragraphize) html = this.paragraphize.load(html);
27408
27409					// verified
27410					html = this.clean.setVerified(html);
27411
27412					// convert inline tags
27413					html = this.clean.convertInline(html);
27414
27415					html = html.replace(/&amp;/g, '&');
27416
27417					return html;
27418				},
27419				onSync: function(html)
27420				{
27421					// remove spaces
27422					html = html.replace(/\u200B/g, '');
27423					html = html.replace(/&#x200b;/gi, '');
27424
27425					if (this.opts.cleanSpaces)
27426					{
27427						html = html.replace(/&nbsp;/gi, ' ');
27428					}
27429
27430					if (html.search(/^<p>(||\s||<br\s?\/?>||&nbsp;)<\/p>$/i) != -1)
27431					{
27432						return '';
27433					}
27434
27435					// reconvert script tag
27436					html = html.replace(/<pre class="redactor-script-tag" style="display: none;"(.*?[^>]?)>([\w\W]*?)<\/pre>/gi, '<script$1>$2</script>');
27437
27438					// restore form tag
27439					html = this.clean.restoreFormTags(html);
27440
27441					var chars = {
27442						'\u2122': '&trade;',
27443						'\u00a9': '&copy;',
27444						'\u2026': '&hellip;',
27445						'\u2014': '&mdash;',
27446						'\u2010': '&dash;'
27447					};
27448					// replace special characters
27449					$.each(chars, function(i,s)
27450					{
27451						html = html.replace(new RegExp(i, 'g'), s);
27452					});
27453
27454					// remove last br in FF
27455					if (this.utils.browser('mozilla'))
27456					{
27457						html = html.replace(/<br\s?\/?>$/gi, '');
27458					}
27459
27460					// remove br in|of li tags
27461					html = html.replace(new RegExp('<br\\s?/?></li>', 'gi'), '</li>');
27462					html = html.replace(new RegExp('</li><br\\s?/?>', 'gi'), '</li>');
27463
27464					// remove empty attributes
27465					html = html.replace(/<(.*?)rel="\s*?"(.*?[^>]?)>/gi, '<$1$2">');
27466					html = html.replace(/<(.*?)style="\s*?"(.*?[^>]?)>/gi, '<$1$2">');
27467					html = html.replace(/="">/gi, '>');
27468					html = html.replace(/""">/gi, '">');
27469					html = html.replace(/"">/gi, '">');
27470
27471					// remove verified
27472					html = html.replace(/<div(.*?)data-tagblock="redactor"(.*?[^>])>/gi, '<div$1$2>');
27473					html = html.replace(/<(.*?) data-verified="redactor"(.*?[^>])>/gi, '<$1$2>');
27474
27475					var $div = $("<div/>").html($.parseHTML(html, document, true));
27476					$div.find("span").removeAttr("rel");
27477
27478					$div.find('pre .redactor-invisible-space').each(function()
27479					{
27480						$(this).contents().unwrap();
27481					});
27482
27483					html = $div.html();
27484
27485					// remove rel attribute from img
27486					html = html.replace(/<img(.*?[^>])rel="(.*?[^>])"(.*?[^>])>/gi, '<img$1$3>');
27487					html = html.replace(/<span class="redactor-invisible-space">(.*?)<\/span>/gi, '$1');
27488
27489					html = html.replace(/ data-save-url="(.*?[^>])"/gi, '');
27490
27491					// remove image resize
27492					html = html.replace(/<span(.*?)id="redactor-image-box"(.*?[^>])>([\w\W]*?)<img(.*?)><\/span>/gi, '$3<img$4>');
27493					html = html.replace(/<span(.*?)id="redactor-image-resizer"(.*?[^>])>(.*?)<\/span>/gi, '');
27494					html = html.replace(/<span(.*?)id="redactor-image-editter"(.*?[^>])>(.*?)<\/span>/gi, '');
27495
27496					// remove font tag
27497					html = html.replace(/<font(.*?)>/gi, '');
27498					html = html.replace(/<\/font>/gi, '');
27499
27500					// tidy html
27501					html = this.tidy.load(html);
27502
27503					// link nofollow
27504					if (this.opts.linkNofollow)
27505					{
27506						html = html.replace(/<a(.*?)rel="nofollow"(.*?[^>])>/gi, '<a$1$2>');
27507						html = html.replace(/<a(.*?[^>])>/gi, '<a$1 rel="nofollow">');
27508					}
27509
27510					// reconvert inline
27511					html = html.replace(/\sdata-redactor-(tag|class|style)="(.*?[^>])"/gi, '');
27512					html = html.replace(new RegExp('<(.*?) data-verified="redactor"(.*?[^>])>', 'gi'), '<$1$2>');
27513					html = html.replace(new RegExp('<(.*?) data-verified="redactor">', 'gi'), '<$1>');
27514
27515					html = html.replace(/&amp;/g, '&');
27516
27517					return html;
27518				},
27519				onPaste: function(html, setMode)
27520				{
27521					html = $.trim(html);
27522					html = html.replace(/\$/g, '&#36;');
27523
27524					// convert dirty spaces
27525					html = html.replace(/<span class="s[0-9]">/gi, '<span>');
27526					html = html.replace(/<span class="Apple-converted-space">&nbsp;<\/span>/gi, ' ');
27527					html = html.replace(/<span class="Apple-tab-span"[^>]*>\t<\/span>/gi, '\t');
27528					html = html.replace(/<span[^>]*>(\s|&nbsp;)<\/span>/gi, ' ');
27529
27530					if (this.opts.pastePlainText)
27531					{
27532						return this.clean.getPlainText(html);
27533					}
27534
27535					if (!this.utils.isSelectAll() && typeof setMode == 'undefined')
27536					{
27537						if (this.utils.isCurrentOrParent(['FIGCAPTION', 'A']))
27538						{
27539							return this.clean.getPlainText(html, false);
27540						}
27541
27542						if (this.utils.isCurrentOrParent('PRE'))
27543						{
27544							html = html.replace(/”/g, '"');
27545							html = html.replace(/“/g, '"');
27546							html = html.replace(/‘/g, '\'');
27547							html = html.replace(/’/g, '\'');
27548
27549							return this.clean.getPreCode(html);
27550						}
27551
27552						if (this.utils.isCurrentOrParent(['BLOCKQUOTE', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6']))
27553						{
27554							html = this.clean.getOnlyImages(html);
27555
27556							if (!this.utils.browser('msie'))
27557							{
27558								var block = this.selection.getBlock();
27559								if (block && block.tagName == 'P')
27560								{
27561									html = html.replace(/<img(.*?)>/gi, '<p><img$1></p>');
27562								}
27563							}
27564
27565							return html;
27566						}
27567
27568						if (this.utils.isCurrentOrParent(['TD']))
27569						{
27570							html = this.clean.onPasteTidy(html, 'td');
27571
27572							if (this.opts.linebreaks) html = this.clean.replaceParagraphsToBr(html);
27573
27574							html = this.clean.replaceDivsToBr(html);
27575
27576							return html;
27577						}
27578
27579
27580						if (this.utils.isCurrentOrParent(['LI']))
27581						{
27582							return this.clean.onPasteTidy(html, 'li');
27583						}
27584					}
27585
27586
27587					html = this.clean.isSingleLine(html, setMode);
27588
27589					if (!this.clean.singleLine)
27590					{
27591						if (this.opts.linebreaks)  html = this.clean.replaceParagraphsToBr(html);
27592						if (this.opts.replaceDivs) html = this.clean.replaceDivs(html);
27593
27594						html = this.clean.saveFormTags(html);
27595					}
27596
27597
27598					html = this.clean.onPasteWord(html);
27599					html = this.clean.onPasteExtra(html);
27600
27601					html = this.clean.onPasteTidy(html, 'all');
27602
27603
27604					// paragraphize
27605					if (!this.clean.singleLine && this.opts.paragraphize)
27606					{
27607						html = this.paragraphize.load(html);
27608					}
27609
27610					html = this.clean.removeDirtyStyles(html);
27611					html = this.clean.onPasteRemoveSpans(html);
27612					html = this.clean.onPasteRemoveEmpty(html);
27613
27614
27615					html = this.clean.convertInline(html);
27616
27617					return html;
27618				},
27619				onPasteWord: function(html)
27620				{
27621					// comments
27622					html = html.replace(/<!--[\s\S]*?-->/gi, '');
27623
27624					// style
27625					html = html.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '');
27626
27627					// op
27628					html = html.replace(/<o\:p[^>]*>[\s\S]*?<\/o\:p>/gi, '');
27629
27630					if (html.match(/class="?Mso|style="[^"]*\bmso-|style='[^'']*\bmso-|w:WordDocument/i))
27631					{
27632						// comments
27633						html = html.replace(/<!--[\s\S]+?-->/gi, '');
27634
27635						// scripts
27636						html = html.replace(/<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi, '');
27637
27638						// Convert <s> into <strike>
27639						html = html.replace(/<(\/?)s>/gi, "<$1strike>");
27640
27641						// Replace nbsp entites to char since it's easier to handle
27642						html = html.replace(/ /gi, ' ');
27643
27644						// Convert <span style="mso-spacerun:yes">___</span> to string of alternating
27645						// breaking/non-breaking spaces of same length
27646						html = html.replace(/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi, function(str, spaces) {
27647							return (spaces.length > 0) ? spaces.replace(/./, " ").slice(Math.floor(spaces.length/2)).split("").join("\u00a0") : '';
27648						});
27649
27650						html = this.clean.onPasteIeFixLinks(html);
27651
27652						// shapes
27653						html = html.replace(/<img(.*?)v:shapes=(.*?)>/gi, '');
27654						html = html.replace(/src="file\:\/\/(.*?)"/, 'src=""');
27655
27656						// lists
27657						var $div = $("<div/>").html(html);
27658
27659						var lastList = false;
27660						var lastLevel = 1;
27661						var listsIds = [];
27662
27663						$div.find("p[style]").each(function()
27664						{
27665							var matches = $(this).attr('style').match(/mso\-list\:l([0-9]+)\slevel([0-9]+)/);
27666
27667							if (matches)
27668							{
27669								var currentList = parseInt(matches[1]);
27670								var currentLevel = parseInt(matches[2]);
27671								var listType = $(this).html().match(/^[\w]+\./) ? "ol" : "ul";
27672
27673								var $li = $("<li/>").html($(this).html());
27674
27675								$li.html($li.html().replace(/^([\w\.]+)</, '<'));
27676								$li.find("span:first").remove();
27677
27678								if (currentLevel == 1 && $.inArray(currentList, listsIds) == -1)
27679								{
27680									var $list = $("<" + listType + "/>").attr({"data-level": currentLevel,
27681																			   "data-list": currentList})
27682																	  .html($li);
27683
27684									$(this).replaceWith($list);
27685
27686									lastList = currentList;
27687									listsIds.push(currentList);
27688								}
27689								else
27690								{
27691									if (currentLevel > lastLevel)
27692									{
27693										var $prevList = $div.find('[data-level="' + lastLevel + '"][data-list="' + lastList + '"]');
27694
27695										var $lastList = $prevList;
27696
27697										for(var i = lastLevel; i < currentLevel; i++)
27698										{
27699											$list = $("<" + listType + "/>");
27700
27701											$list.appendTo($lastList.find("li").last());
27702
27703											$lastList = $list;
27704										}
27705
27706										$lastList.attr({"data-level": currentLevel,
27707														"data-list": currentList})
27708												 .html($li);
27709
27710									}
27711									else
27712									{
27713										var $prevList = $div.find('[data-level="' + currentLevel + '"][data-list="' + currentList + '"]').last();
27714
27715										$prevList.append($li);
27716									}
27717
27718									lastLevel = currentLevel;
27719									lastList = currentList;
27720
27721									$(this).remove();
27722								}
27723							}
27724						});
27725
27726						$div.find('[data-level][data-list]').removeAttr('data-level data-list');
27727						html = $div.html();
27728
27729						// remove ms word's bullet
27730						html = html.replace(/·/g, '');
27731						html = html.replace(/<p class="Mso(.*?)"/gi, '<p');
27732
27733						// classes
27734						html = html.replace(/ class=\"(mso[^\"]*)\"/gi,	"");
27735						html = html.replace(/ class=(mso\w+)/gi, "");
27736
27737						// remove ms word tags
27738						html = html.replace(/<o:p(.*?)>([\w\W]*?)<\/o:p>/gi, '$2');
27739
27740						// ms word break lines
27741						html = html.replace(/\n/g, ' ');
27742
27743						// ms word lists break lines
27744						html = html.replace(/<p>\n?<li>/gi, '<li>');
27745					}
27746
27747					return html;
27748				},
27749				onPasteExtra: function(html)
27750				{
27751					// remove google docs markers
27752					html = html.replace(/<b\sid="internal-source-marker(.*?)">([\w\W]*?)<\/b>/gi, "$2");
27753					html = html.replace(/<b(.*?)id="docs-internal-guid(.*?)">([\w\W]*?)<\/b>/gi, "$3");
27754
27755					// google docs styles
27756			 		html = html.replace(/<span[^>]*(font-style: italic; font-weight: bold|font-weight: bold; font-style: italic)[^>]*>/gi, '<span style="font-weight: bold;"><span style="font-style: italic;">');
27757			 		html = html.replace(/<span[^>]*font-style: italic[^>]*>/gi, '<span style="font-style: italic;">');
27758					html = html.replace(/<span[^>
27758]*font-weight: bold[^>]*>/gi, '<span style="font-weight: bold;">');
27759					html = html.replace(/<span[^>]*text-decoration: underline[^>]*>/gi, '<span style="text-decoration: underline;">');
27760
27761					html = html.replace(/<img>/gi, '');
27762					html = html.replace(/\n{3,}/gi, '\n');
27763					html = html.replace(/<font(.*?)>([\w\W]*?)<\/font>/gi, '$2');
27764
27765					// remove dirty p
27766					html = html.replace(/<p><p>/gi, '<p>');
27767					html = html.replace(/<\/p><\/p>/gi, '</p>');
27768					html = html.replace(/<li>(\s*|\t*|\n*)<p>/gi, '<li>');
27769					html = html.replace(/<\/p>(\s*|\t*|\n*)<\/li>/gi, '</li>');
27770
27771					// remove space between paragraphs
27772					html = html.replace(/<\/p>\s<p/gi, '<\/p><p');
27773
27774					// remove safari local images
27775					html = html.replace(/<img src="webkit-fake-url\:\/\/(.*?)"(.*?)>/gi, '');
27776
27777					// bullets
27778					html = html.replace(/<p>•([\w\W]*?)<\/p>/gi, '<li>$1</li>');
27779
27780					// FF fix
27781					if (this.utils.browser('mozilla'))
27782					{
27783						html = html.replace(/<br\s?\/?>$/gi, '');
27784					}
27785
27786					return html;
27787				},
27788				onPasteTidy: function(html, type)
27789				{
27790					// remove all tags except these
27791					var tags = ['span', 'a', 'pre', 'blockquote', 'small', 'em', 'strong', 'code', 'kbd', 'mark', 'address', 'cite', 'var', 'samp', 'dfn', 'sup', 'sub', 'b', 'i', 'u', 'del',
27792								'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'p', 'br', 'video', 'audio', 'iframe', 'embed', 'param', 'object', 'img', 'table',
27793								'td', 'th', 'tr', 'tbody', 'tfoot', 'thead', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
27794					var tagsEmpty = false;
27795					var attrAllowed =  [
27796							['a', '*'],
27797							['img', ['src', 'alt']],
27798							['span', ['class', 'rel', 'data-verified']],
27799							['iframe', '*'],
27800							['video', '*'],
27801							['audio', '*'],
27802							['embed', '*'],
27803							['object', '*'],
27804							['param', '*'],
27805							['source', '*']
27806						];
27807
27808					if (type == 'all')
27809					{
27810						tagsEmpty = ['p', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
27811						attrAllowed =  [
27812							['table', 'class'],
27813							['td', ['colspan', 'rowspan']],
27814							['a', '*'],
27815							['img', ['src', 'alt', 'data-redactor-inserted-image']],
27816							['span', ['class', 'rel', 'data-verified']],
27817							['iframe', '*'],
27818							['video', '*'],
27819							['audio', '*'],
27820							['embed', '*'],
27821							['object', '*'],
27822							['param', '*'],
27823							['source', '*']
27824						];
27825					}
27826					else if (type == 'td')
27827					{
27828						// remove all tags except these and remove all table tags: tr, td etc
27829						tags = ['ul', 'ol', 'li', 'span', 'a', 'small', 'em', 'strong', 'code', 'kbd', 'mark', 'cite', 'var', 'samp', 'dfn', 'sup', 'sub', 'b', 'i', 'u', 'del',
27830								'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'br', 'iframe', 'video', 'audio', 'embed', 'param', 'object', 'img', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
27831
27832					}
27833					else if (type == 'li')
27834					{
27835						// only inline tags and ul, ol, li
27836						tags = ['ul', 'ol', 'li', 'span', 'a', 'small', 'em', 'strong', 'code', 'kbd', 'mark', 'cite', 'var', 'samp', 'dfn', 'sup', 'sub', 'b', 'i', 'u', 'del', 'br',
27837								'iframe', 'video', 'audio', 'embed', 'param', 'object', 'img'];
27838					}
27839
27840					var options = {
27841						deniedTags: (this.opts.deniedTags) ? this.opts.deniedTags : false,
27842						allowedTags: (this.opts.allowedTags) ? this.opts.allowedTags : tags,
27843						removeComments: true,
27844						removePhp: true,
27845						removeAttr: (this.opts.removeAttr) ? this.opts.removeAttr : false,
27846						allowedAttr: (this.opts.allowedAttr) ? this.opts.allowedAttr : attrAllowed,
27847						removeEmpty: tagsEmpty
27848					};
27849
27850					return this.tidy.load(html, options);
27851				},
27852				onPasteRemoveEmpty: function(html)
27853				{
27854					html = html.replace(/<(p|h[1-6])>(|\s|\n|\t|<br\s?\/?>)<\/(p|h[1-6])>/gi, '');
27855
27856					// remove br in the end
27857					if (!this.opts.linebreaks) html = html.replace(/<br>$/i, '');
27858
27859					return html;
27860				},
27861				onPasteRemoveSpans: function(html)
27862				{
27863					html = html.replace(/<span>(.*?)<\/span>/gi, '$1');
27864					html = html.replace(/<span[^>]*>\s|&nbsp;<\/span>/gi, ' ');
27865
27866					return html;
27867				},
27868				onPasteIeFixLinks: function(html)
27869				{
27870					if (!this.utils.browser('msie')) return html;
27871
27872					var tmp = $.trim(html);
27873					if (tmp.search(/^<a(.*?)>(.*?)<\/a>$/i) === 0)
27874					{
27875						html = html.replace(/^<a(.*?)>(.*?)<\/a>$/i, "$2");
27876					}
27877
27878					return html;
27879				},
27880				isSingleLine: function(html, setMode)
27881				{
27882					this.clean.singleLine = false;
27883
27884					if (!this.utils.isSelectAll() && typeof setMode == 'undefined')
27885					{
27886						var blocks = this.opts.blockLevelElements.join('|').replace('P|', '').replace('DIV|', '');
27887
27888						var matchBlocks = html.match(new RegExp('</(' + blocks + ')>', 'gi'));
27889						var matchContainers = html.match(/<\/(p|div)>/gi);
27890
27891						if (!matchBlocks && (matchContainers === null || (matchContainers && matchContainers.length <= 1)))
27892						{
27893							var matchBR = html.match(/<br\s?\/?>/gi);
27894							//var matchIMG = html.match(/<img(.*?[^>])>/gi);
27895							if (!matchBR)
27896							{
27897								this.clean.singleLine = true;
27898								html = html.replace(/<\/?(p|div)(.*?)>/gi, '');
27899							}
27900						}
27901					}
27902
27903					return html;
27904				},
27905				stripTags: function(input, allowed)
27906				{
27907				    allowed = (((allowed || '') + '').toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join('');
27908				    var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi;
27909
27910				    return input.replace(tags, function ($0, $1) {
27911				        return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
27912				    });
27913				},
27914				savePreCode: function(html)
27915				{
27916					html = this.clean.savePreFormatting(html);
27917					html = this.clean.saveCodeFormatting(html);
27918
27919					html = this.clean.restoreSelectionMarker(html);
27920
27921					return html;
27922				},
27923				savePreFormatting: function(html)
27924				{
27925					var pre = html.match(/<pre(.*?)>([\w\W]*?)<\/pre>/gi);
27926
27927					if (pre !== null)
27928					{
27929						$.each(pre, $.proxy(function(i,s)
27930						{
27931							var arr = s.match(/<pre(.*?)>([\w\W]*?)<\/pre>/i);
27932
27933							arr[2] = arr[2].replace(/<br\s?\/?>/g, '\n');
27934							arr[2] = arr[2].replace(/&nbsp;/g, ' ');
27935
27936							if (this.opts.preSpaces)
27937							{
27938								arr[2] = arr[2].replace(/\t/g, Array(this.opts.preSpaces + 1).join(' '));
27939							}
27940
27941							arr[2] = this.clean.encodeEntities(arr[2]);
27942
27943							// $ fix
27944							arr[2] = arr[2].replace(/\$/g, '&#36;');
27945
27946							html = html.replace(s, '<pre' + arr[1] + '>' + arr[2] + '</pre>');
27947
27948						}, this));
27949					}
27950
27951					return html;
27952				},
27953				saveCodeFormatting: function(html)
27954				{
27955					var code = html.match(/<code(.*?)>([\w\W]*?)<\/code>/gi);
27956
27957					if (code !== null)
27958					{
27959						$.each(code, $.proxy(function(i,s)
27960						{
27961							var arr = s.match(/<code(.*?)>([\w\W]*?)<\/code>/i);
27962
27963							arr[2] = arr[2].replace(/&nbsp;/g, ' ');
27964							arr[2] = this.clean.encodeEntities(arr[2]);
27965							arr[2] = arr[2].replace(/\$/g, '&#36;');
27966
27967							html = html.replace(s, '<code' + arr[1] + '>' + arr[2] + '</code>');
27968						}, this));
27969					}
27970
27971					return html;
27972				},
27973				restoreSelectionMarker: function(html)
27974				{
27975					html = html.replace(/&lt;span id=&quot;selection-marker-([0-9])&quot; class=&quot;redactor-selection-marker&quot; data-verified=&quot;redactor&quot;&gt;​&lt;\/span&gt;/g, '<span id="selection-marker-$1" class="redactor-selection-marker" data-verified="redactor">​</span>');
27976
27977					return html;
27978				},
27979				getTextFromHtml: function(html)
27980				{
27981					html = html.replace(/<br\s?\/?>|<\/H[1-6]>|<\/p>|<\/div>|<\/li>|<\/td>/gi, '\n');
27982
27983					var tmp = document.createElement('div');
27984					tmp.innerHTML = html;
27985					html = tmp.textContent || tmp.innerText;
27986
27987					return $.trim(html);
27988				},
27989				getPlainText: function(html, paragraphize)
27990				{
27991					html = this.clean.getTextFromHtml(html);
27992					html = html.replace(/\n\s*\n/g, "\n");
27993					html = html.replace(/\n\n/g, "\n");
27994					html = html.replace(/\n/g, '<br />');
27995
27996					if (this.opts.paragraphize && typeof paragraphize == 'undefined' && !this.utils.browser('mozilla'))
27997					{
27998						html = this.paragraphize.load(html);
27999					}
28000
28001					return html;
28002				},
28003				getPreCode: function(html)
28004				{
28005					html = html.replace(/<img(.*?) style="(.*?)"(.*?[^>])>/gi, '<img$1$3>');
28006					html = html.replace(/<img(.*?)>/gi, '&lt;img$1&gt;');
28007					html = this.clean.getTextFromHtml(html);
28008
28009					if (this.opts.preSpaces)
28010					{
28011						html = html.replace(/\t/g, Array(this.opts.preSpaces + 1).join(' '));
28012					}
28013
28014					html = this.clean.encodeEntities(html);
28015
28016					return html;
28017				},
28018				getOnlyImages: function(html)
28019				{
28020					html = html.replace(/<img(.*?)>/gi, '[img$1]');
28021
28022					// remove all tags
28023					html = html.replace(/<([Ss]*?)>/gi, '');
28024
28025					html = html.replace(/\[img(.*?)\]/gi, '<img$1>');
28026
28027					return html;
28028				},
28029				getOnlyLinksAndImages: function(html)
28030				{
28031					html = html.replace(/<a(.*?)href="(.*?)"(.*?)>([\w\W]*?)<\/a>/gi, '[a href="$2"]$4[/a]');
28032					html = html.replace(/<img(.*?)>/gi, '[img$1]');
28033
28034					// remove all tags
28035					html = html.replace(/<(.*?)>/gi, '');
28036
28037					html = html.replace(/\[a href="(.*?)"\]([\w\W]*?)\[\/a\]/gi, '<a href="$1">$2</a>');
28038					html = html.replace(/\[img(.*?)\]/gi, '<img$1>');
28039
28040					return html;
28041				},
28042				encodeEntities: function(str)
28043				{
28044					str = String(str).replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"');
28045					return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
28046				},
28047				removeDirtyStyles: function(html)
28048				{
28049					if (this.utils.browser('msie')) return html;
28050
28051					var div = document.createElement('div');
28052					div.innerHTML = html;
28053
28054					this.clean.clearUnverifiedRemove($(div));
28055
28056					html = div.innerHTML;
28057					$(div).remove();
28058
28059					return html;
28060				},
28061				clearUnverified: function()
28062				{
28063					if (this.utils.browser('msie')) return;
28064
28065					this.clean.clearUnverifiedRemove(this.$editor);
28066
28067					var headers = this.$editor.find('h1, h2, h3, h4, h5, h6');
28068					headers.find('span').removeAttr('style');
28069					headers.find(this.opts.verifiedTags.join(', ')).removeAttr('style');
28070
28071					this.code.sync();
28072				},
28073				clearUnverifiedRemove: function($editor)
28074				{
28075					$editor.find(this.opts.verifiedTags.join(', ')).removeAttr('style');
28076					$editor.find('span').not('[data-verified="redactor"]').removeAttr('style');
28077
28078					$editor.find('span[data-verified="redactor"], img[data-verified="redactor"]').each(function(i, s)
28079					{
28080						var $s = $(s);
28081						$s.attr('style', $s.attr('rel'));
28082					});
28083
28084				},
28085				cleanEmptyParagraph: function()
28086				{
28087
28088				},
28089				setVerified: function(html)
28090				{
28091					if (this.utils.browser('msie')) return html;
28092
28093					html = html.replace(new RegExp('<img(.*?[^>])>
28093', 'gi'), '<img$1 data-verified="redactor">');
28094					html = html.replace(new RegExp('<span(.*?[^>])>', 'gi'), '<span$1 data-verified="redactor">');
28095
28096					var matches = html.match(new RegExp('<(span|img)(.*?)style="(.*?)"(.*?[^>])>', 'gi'));
28097
28098					if (matches)
28099					{
28100						var len = matches.length;
28101						for (var i = 0; i < len; i++)
28102						{
28103							try {
28104
28105								var newTag = matches[i].replace(/style="(.*?)"/i, 'style="$1" rel="$1"');
28106								html = html.replace(matches[i], newTag);
28107
28108							}
28109							catch (e) {}
28110						}
28111					}
28112
28113					return html;
28114				},
28115				convertInline: function(html)
28116				{
28117					var $div = $('<div />').html(html);
28118
28119					var tags = this.opts.inlineTags;
28120					tags.push('span');
28121
28122					$div.find(tags.join(',')).each(function()
28123					{
28124						var $el = $(this);
28125						var tag = this.tagName.toLowerCase();
28126						$el.attr('data-redactor-tag', tag);
28127
28128						if (tag == 'span')
28129						{
28130							if ($el.attr('style')) $el.attr('data-redactor-style', $el.attr('style'));
28131							else if ($el.attr('class')) $el.attr('data-redactor-class', $el.attr('class'));
28132						}
28133
28134					});
28135
28136					html = $div.html();
28137					$div.remove();
28138
28139					return html;
28140				},
28141				normalizeLists: function()
28142				{
28143					this.$editor.find('li').each(function(i,s)
28144					{
28145						var $next = $(s).next();
28146						if ($next.length !== 0 && ($next[0].tagName == 'UL' || $next[0].tagName == 'OL'))
28147						{
28148							$(s).append($next);
28149						}
28150
28151					});
28152				},
28153				removeSpaces: function(html)
28154				{
28155					html = html.replace(/\n/g, '');
28156					html = html.replace(/[\t]*/g, '');
28157					html = html.replace(/\n\s*\n/g, "\n");
28158					html = html.replace(/^[\s\n]*/g, ' ');
28159					html = html.replace(/[\s\n]*$/g, ' ');
28160					html = html.replace( />\s{2,}</g, '> <'); // between inline tags can be only one space
28161					html = html.replace(/\n\n/g, "\n");
28162					html = html.replace(/\u200B/g, '');
28163
28164					return html;
28165				},
28166				replaceDivs: function(html)
28167				{
28168					if (this.opts.linebreaks)
28169					{
28170						html = html.replace(/<div><br\s?\/?><\/div>/gi, '<br />');
28171						html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '$2<br />');
28172					}
28173					else
28174					{
28175						html = html.replace(/<div(.*?)>([\w\W]*?)<\/div>/gi, '<p$1>$2</p>');
28176					}
28177
28178					html = html.replace(/<div(.*?[^>])>/gi, '');
28179					html = html.replace(/<\/div>/gi, '');
28180
28181					return html;
28182				},
28183				replaceDivsToBr: function(html)
28184				{
28185					html = html.replace(/<div\s(.*?)>/gi, '<p>');
28186					html = html.replace(/<div><br\s?\/?><\/div>/gi, '<br /><br />');
28187					html = html.replace(/<div>([\w\W]*?)<\/div>/gi, '$1<br /><br />');
28188
28189					return html;
28190				},
28191				replaceParagraphsToBr: function(html)
28192				{
28193					html = html.replace(/<p\s(.*?)>/gi, '<p>');
28194					html = html.replace(/<p><br\s?\/?><\/p>/gi, '<br />');
28195					html = html.replace(/<p>([\w\W]*?)<\/p>/gi, '$1<br /><br />');
28196					html = html.replace(/(<br\s?\/?>){1,}\n?<\/blockquote>/gi, '</blockquote>');
28197
28198					return html;
28199				},
28200				saveFormTags: function(html)
28201				{
28202					return html.replace(/<form(.*?)>([\w\W]*?)<\/form>/gi, '<section$1 rel="redactor-form-tag">$2</section>');
28203				},
28204				restoreFormTags: function(html)
28205				{
28206					return html.replace(/<section(.*?) rel="redactor-form-tag"(.*?)>([\w\W]*?)<\/section>/gi, '<form$1$2>$3</form>');
28207				}
28208			};
28209		},
28210		code: function()
28211		{
28212			return {
28213				set: function(html)
28214				{
28215					html = $.trim(html.toString());
28216
28217					// clean
28218					html = this.clean.onSet(html);
28219
28220
28221					if (this.utils.browser('msie'))
28222					{
28223						html = html.replace(/<span(.*?)id="selection-marker-(1|2)"(.*?)><\/span>/gi, '');
28224					}
28225
28226					this.$editor.html(html);
28227					this.code.sync();
28228
28229					if (html !== '') this.placeholder.remove();
28230
28231					setTimeout($.proxy(this.buffer.add, this), 15);
28232					if (this.start === false) this.observe.load();
28233
28234				},
28235				get: function()
28236				{
28237					var code = this.$textarea.val();
28238
28239					if (this.opts.replaceDivs) code = this.clean.replaceDivs(code);
28240					if (this.opts.linebreaks) code = this.clean.replaceParagraphsToBr(code);
28241
28242					// indent code
28243					code = this.tabifier.get(code);
28244
28245					return code;
28246				},
28247				sync: function()
28248				{
28249					setTimeout($.proxy(this.code.startSync, this), 10);
28250				},
28251				startSync: function()
28252				{
28253					var html = this.$editor.html();
28254
28255					// is there a need to synchronize
28256					if (this.code.syncCode && this.code.syncCode == html || (this.start && html == '' ))
28257					{
28258						// do not sync
28259						return;
28260					}
28261
28262					// save code
28263					this.code.syncCode = html;
28264
28265					// before clean callback
28266					html = this.core.setCallback('syncBefore', html);
28267
28268					// clean
28269					html = this.clean.onSync(html);
28270
28271					// set code
28272					this.$textarea.val(html);
28273
28274					// after sync callback
28275					this.core.setCallback('sync', html);
28276
28277					if (this.start === false)
28278					{
28279						this.core.setCallback('change', html);
28280					}
28281
28282					this.start = false;
28283
28284					if (this.autosave.html == false)
28285					{
28286						this.autosave.html = this.code.get();
28287					}
28288
28289					if (this.opts.codemirror)
28290					{
28291						this.$textarea.next('.CodeMirror').each(function(i, el)
28292						{
28293							el.CodeMirror.setValue(html);
28294						});
28295					}
28296
28297					//autosave
28298					this.autosave.onChange();
28299					this.autosave.enable();
28300				},
28301				toggle: function()
28302				{
28303					if (this.opts.visual)
28304					{
28305						this.code.showCode();
28306					}
28307					else
28308					{
28309						this.code.showVisual();
28310					}
28311				},
28312				showCode: function()
28313				{
28314					this.selection.save();
28315
28316					this.code.offset = this.caret.getOffset();
28317					var scroll = $(window).scrollTop();
28318
28319					var	width = this.$editor.innerWidth(),
28320						height = this.$editor.innerHeight();
28321
28322					this.$editor.hide();
28323
28324					var html = this.$textarea.val();
28325
28326					this.modified = this.clean.removeSpaces(html);
28327
28328					// indent code
28329					html = this.tabifier.get(html);
28330
28331					// caret position sync
28332					var start = 0, end = 0;
28333					var $editorDiv = $("<div/>").append($.parseHTML(this.clean.onSync(this.$editor.html()), document, true));
28334					var $selectionMarkers = $editorDiv.find("span.redactor-selection-marker");
28335
28336					if ($selectionMarkers.length > 0)
28337					{
28338						var editorHtml = this.tabifier.get($editorDiv.html()).replace(/&amp;/g, '&');
28339
28340						if ($selectionMarkers.length == 1)
28341						{
28342							start = this.utils.strpos(editorHtml, $editorDiv.find("#selection-marker-1").prop("outerHTML"));
28343							end   = start;
28344						}
28345						else if ($selectionMarkers.length == 2)
28346						{
28347							start = this.utils.strpos(editorHtml, $editorDiv.find("#selection-marker-1").prop("outerHTML"));
28348							end	 = this.utils.strpos(editorHtml, $editorDiv.find("#selection-marker-2").prop("outerHTML")) - $editorDiv.find("#selection-marker-1").prop("outerHTML").toString().length;
28349						}
28350					}
28351
28352					this.selection.removeMarkers();
28353					this.$textarea.val(html);
28354
28355					if (this.opts.codemirror)
28356					{
28357						this.$textarea.next('.CodeMirror').each(function(i, el)
28358						{
28359							$(el).show();
28360							el.CodeMirror.setValue(html);
28361							el.CodeMirror.setSize('100%', height);
28362							el.CodeMirror.refresh();
28363
28364							if (start == end)
28365							{
28366								el.CodeMirror.setCursor(el.CodeMirror.posFromIndex(start).line, el.CodeMirror.posFromIndex(end).ch);
28367							}
28368							else
28369							{
28370								el.CodeMirror.setSelection({line: el.CodeMirror.posFromIndex(start).line,
28371															ch: el.CodeMirror.posFromIndex(start).ch},
28372														  {line: el.CodeMirror.posFromIndex(end).line,
28373														   ch:  el.CodeMirror.posFromIndex(end).ch});
28374							}
28375
28376							el.CodeMirror.focus();
28377						});
28378					}
28379					else
28380					{
28381						this.$textarea.height(height).show().focus();
28382						this.$textarea.on('keydown.redactor-textarea-indenting', this.code.textareaIndenting);
28383
28384						$(window).scrollTop(scroll);
28385
28386						if (this.$textarea[0].setSelectionRange)
28387						{
28388							this.$textarea[0].setSelectionRange(start, end);
28389						}
28390
28391						this.$textarea[0].scrollTop = 0;
28392					}
28393
28394					this.opts.visual = false;
28395
28396					this.button.setInactiveInCode();
28397					this.button.setActive('html');
28398					this.core.setCallback('source', html);
28399				},
28400				showVisual: function()
28401				{
28402					var html;
28403
28404					if (this.opts.visual) return;
28405
28406					var start = 0, end = 0;
28407
28408					if (this.opts.codemirror)
28409					{
28410						var selection;
28411
28412						this.$textarea.next('.CodeMirror').each(function(i, el)
28413						{
28414							selection = el.CodeMirror.listSelections();
28415
28416							start = el.CodeMirror.indexFromPos(selection[0].anchor);
28417							end = el.CodeMirror.indexFromPos(selection[0].head);
28418
28419							html = el.CodeMirror.getValue();
28420						});
28421					}
28422					else
28423					{
28424						start = this.$textarea.get(0).selectionStart;
28425						end = this.$textarea.get(0).selectionEnd;
28426
28427						html = this.$textarea.hide().val();
28428					}
28429
28430					// if selection starts from end
28431					if (start > end && end > 0)
28432					{
28433						var tempStart = end;
28434						var tempEnd = start;
28435
28436						start = tempStart;
28437						end = tempEnd;
28438					}
28439
28440					start = this.code.enlargeOffset(html, start);
28441					end = this.code.enlargeOffset(html, end);
28442
28443					html = html.substr(0, start) + this.selection.getMarkerAsHtml(1) + html.substr(start);
28444
28445					if (end > start)
28446					{
28447						var markerLength = this.selection.getMarkerAsHtml(1).toString().length;
28448
28449						html = html.substr(0, end + markerLength) + this.selection.getMarkerAsHtml(2) + html.substr(end + markerLength);
28450					}
28451
28452
28453
28454					if (this.modified !== this.clean.removeSpaces(html))
28455					{
28456						this.code.set(html);
28457
28458					}
28459
28460					if (this.opts.codemirror)
28461					{
28462						this.$textarea.next('.CodeMirror').hide();
28463					}
28464
28465					this.$editor.show();
28466
28467					if (!this.utils.isEmpty(html))
28468					{
28469						this.placeholder.remove();
28470					}
28471
28472					this.selection.restore();
28473
28474					this.$textarea.off('keydown.redactor-textarea-indenting');
28475
28476					this.button.setActiveInVisual();
28477					this.button.setInactive('html');
28478					this.observe.load();
28479					this.opts.visual = true;
28480					this.core.setCallback('visual', html);
28481				},
28482				textareaIndenting: function(e)
28483				{
28484					if (e.keyCode !== 9) return true;
28485
28486					var $el = this.$textarea;
28487					var start = $el.get(0).selectionStart;
28488					$el.val($el.val().substring(0, start) + "\t" + $el.val().substring($el.get(0).selectionEnd));
28489					$el.get(0).selectionStart = $el.get(0).selectionEnd = start + 1;
28490
28491					return false;
28492				},
28493				enlargeOffset: function(html, offset)
28494				{
28495					var htmlLength = html.length;
28496					var c = 0;
28497
28498					if (html[offset] == '>')
28499					{
28500						c++;
28501					}
28502					else
28503					{
28504						for(var i = offset; i <= htmlLength; i++)
28505						{
28506							c++;
28507
28508							if (html[i] == '>')
28509							{
28510								break;
28511							}
28512							else if (html[i] == '<' || i == htmlLength)
28513							{
28514								c = 0;
28515								break;
28516							}
28517						}
28518					}
28519
28520					return offset + c;
28521				}
28522			};
28523		},
28524		core: function()
28525		{
28526			return {
28527				getObject: function()
28528				{
28529					return $.extend({}, this);
28530				},
28531				getEditor: function()
28532				{
28533					return this.$editor;
28534				},
28535				getBox: function()
28536				{
28537					return this.$box;
28538				},
28539				getElement: function()
28540				{
28541					return this.$element;
28542				},
28543				getTextarea: function()
28544				{
28545					return this.$textarea;
28546				},
28547				getToolbar: function()
28548				{
28549					return (this.$toolbar) ? this.$toolbar : false;
28550				},
28551				addEvent: function(name)
28552				{
28553					this.core.event = name;
28554				},
28555				getEvent: function()
28556				{
28557					return this.core.event;
28558				},
28559				setCallback: function(type, e, data)
28560				{
28561					var eventName = type + 'Callback';
28562					var eventNamespace = 'redactor';
28563					var callback = this.opts[eventName];
28564
28565					if (this.$textarea)
28566					{
28567						var returnValue = false;
28568						var events = $._data(this.$textarea[0], 'events');
28569
28570						if (typeof events != 'undefined' && typeof events[eventName] != 'undefined')
28571						{
28572							$.each(events[eventName], $.proxy(function(key, value)
28573							{
28574								if (value['namespace'] == eventNamespace)
28575								{
28576									var data = (typeof data == 'undefined') ? [e] : [e, data];
28577
28578									returnValue = (typeof data == 'undefined') ? value.handler.call(this, e) : value.handler.call(this, e, data);
28579								}
28580							}, this));
28581						}
28582
28583						if (returnValue) return returnValue;
28584					}
28585
28586					if ($.isFunction(callback))
28587					{
28588						return (typeof data == 'undefined') ? callback.call(this, e) : callback.call(this, e, data);
28589					}
28590					else
28591					{
28592						return (typeof data == 'undefined') ? e : data;
28593					}
28594				},
28595				destroy: function()
28596				{
28597					this.opts.destroyed = true;
28598
28599					this.core.setCallback('destroy');
28600
28601					// off events and remove data
28602					this.$element.off('.redactor').removeData('redactor');
28603					this.$editor.off('.redactor');
28604
28605					$(document).off('mousedown.redactor-blur.' + this.uuid);
28606					$(document).off('mousedown.redactor.' + this.uuid);
28607					$(document).off('click.redactor-image-delete.' + this.uuid);
28608					$(document).off('click.redactor-image-resize-hide.' + this.uuid);
28609					$(document).off('touchstart.redactor.' + this.uuid + ' click.redactor.' + this.uuid);
28610					$("body").off('scroll.redactor.' + this.uuid);
28611					$(this.opts.toolbarFixedTarget).off('scroll.redactor.' + this.uuid);
28612
28613					// common
28614					this.$editor.removeClass('redactor-editor redactor-linebreaks redactor-placeholder');
28615					this.$editor.removeAttr('contenteditable');
28616
28617					var html = this.code.get();
28618
28619					if (this.opts.toolbar)
28620					{
28621						// dropdowns off
28622						this.$toolbar.find('a').each(function()
28623						{
28624							var $el = $(this);
28625							if ($el.data('dropdown'))
28626							{
28627								$el.data('dropdown').remove();
28628								$el.data('dropdown', {});
28629							}
28630						});
28631					}
28632
28633					if (this.build.isTextarea())
28634					{
28635						this.$box.after(this.$element);
28636						this.$box.remove();
28637						this.$element.val(html).show();
28638					}
28639					else
28640					{
28641						this.$box.after(this.$editor);
28642						this.$box.remove();
28643						this.$element.html(html).show();
28644					}
28645
28646					// paste box
28647					if (this.$pasteBox) this.$pasteBox.remove();
28648
28649					// modal
28650					if (this.$modalBox) this.$modalBox.remove();
28651					if (this.$modalOverlay) this.$modalOverlay.remove();
28652
28653					// buttons tooltip
28654					$('.redactor-toolbar-tooltip-' + this.uuid).remove();
28655
28656					// autosave
28657					clearInterval(this.autosaveInterval);
28658				}
28659			};
28660		},
28661		dropdown: function()
28662		{
28663			return {
28664				build: function(name, $dropdown, dropdownObject)
28665				{
28666					if (name == 'formatting' && this.opts.formattingAdd)
28667					{
28668						$.each(this.opts.formattingAdd, $.proxy(function(i,s)
28669						{
28670							var name = s.tag,
28671								func;
28672
28673							if (typeof s['class'] != 'undefined')
28674							{
28675								name = name + '-' + s['class'];
28676							}
28677
28678							s.type = (this.utils.isBlockTag(s.tag)) ? 'block' : 'inline';
28679
28680							if (typeof s.func !== "undefined")
28681							{
28682								func = s.func;
28683							}
28684							else
28685							{
28686								func = (s.type == 'inline') ? 'inline.formatting' : 'block.formatting';
28687							}
28688
28689							if (this.opts.linebreaks && s.type == 'block' && s.tag == 'p') return;
28690
28691							this.formatting[name] = {
28692								tag: s.tag,
28693								style: s.style,
28694								'class': s['class'],
28695								attr: s.attr,
28696								data: s.data,
28697								clear: s.clear
28698							};
28699
28700							dropdownObject[name] = {
28701								func: func,
28702								title: s.title
28703							};
28704
28705						}, this));
28706					}
28707
28708					$.each(dropdownObject, $.proxy(function(btnName, btnObject)
28709					{
28710						var $item = $('<a href="#" class="redactor-dropdown-' + btnName + '" role="button">' + btnObject.title + '</a>');
28711						if (name == 'formatting') $item.addClass('redactor-formatting-' + btnName);
28712
28713						$item.on('click', $.proxy(function(e)
28714						{
28715							e.preventDefault();
28716
28717							var type = 'func';
28718							var callback = btnObject.func;
28719							if (btnObject.command)
28720							{
28721								type = 'command';
28722								callback = btnObject.command;
28723							}
28724							else if (btnObject.dropdown)
28725							{
28726								type = 'dropdown';
28727								callback = btnObject.dropdown;
28728							}
28729
28730							if ($(e.target).hasClass('redactor-dropdown-link-inactive')) return;
28731
28732							this.button.onClick(e, btnName, type, callback);
28733							this.dropdown.hideAll();
28734
28735						}, this));
28736
28737						this.observe.addDropdown($item, btnName, btnObject);
28738
28739						$dropdown.append($item);
28740
28741					}, this));
28742				},
28743				show: function(e, key)
28744				{
28745					if (!this.opts.visual)
28746					{
28747						e.preventDefault();
28748						return false;
28749					}
28750
28751					var $button = this.button.get(key);
28752
28753					// Always re-append it to the end of <body> so it always has the highest sub-z-index.
28754					var $dropdown = $button.data('dropdown').appendTo(document.body);
28755
28756					if (this.opts.highContrast)
28757					{
28758						$dropdown.addClass("redactor-dropdown-contrast");
28759					}
28760
28761					if ($button.hasClass('dropact'))
28762					{
28763						this.dropdown.hideAll();
28764					}
28765					else
28766					{
28767						this.dropdown.hideAll();
28768						this.observe.dropdowns();
28769
28770						this.core.setCallback('dropdownShow', { dropdown: $dropdown, key: key, button: $button });
28771
28772						this.button.setActive(key);
28773
28774						$button.addClass('dropact');
28775
28776						var keyPosition = $button.offset();
28777
28778						// fix right placement
28779						var dropdownWidth = $dropdown.width();
28780						if ((keyPosition.left + dropdownWidth) > $(document).width())
28781						{
28782							keyPosition.left = Math.max(0, keyPosition.left - dropdownWidth);
28783						}
28784
28785						var left = keyPosition.left + 'px';
28786						if (this.$toolbar.hasClass('toolbar-fixed-box'))
28787						{
28788							var top = this.$toolbar.innerHeight() + this.opts.toolbarFixedTopOffset;
28789							var position = 'fixed';
28790							if (this.opts.toolbarFixedTarget !== document)
28791							{
28792								top = (this.$toolbar.innerHeight() + this.$toolbar.offset().top) + this.opts.toolbarFixedTopOffset;
28793								position = 'absolute';
28794							}
28795
28796							$dropdown.css({ position: position, left: left, top: top + 'px' }).show();
28797						}
28798						else
28799						{
28800							var top = ($button.innerHeight() + keyPosition.top) + 'px';
28801
28802							$dropdown.css({ position: 'absolute', left: left, top: top }).show();
28803						}
28804
28805						this.core.setCallback('dropdownShown', { dropdown: $dropdown, key: key, button: $button });
28806
28807						this.$dropdown = $dropdown;
28808					}
28809
28810
28811					$(document).one('click.redactor-dropdown', $.proxy(this.dropdown.hide, this));
28812					this.$editor.one('click.redactor-dropdown', $.proxy(this.dropdown.hide, this));
28813					$(document).one('keyup.redactor-dropdown', $.proxy(this.dropdown.closeHandler, this));
28814
28815					// disable scroll whan dropdown scroll
28816					$dropdown.on('mouseover.redactor-dropdown', $.proxy(this.utils.disableBodyScroll, this)).on('mouseout.redactor-dropdown', $.proxy(this.utils.enableBodyScroll, this));
28817
28818					e.stopPropagation();
28819				},
28820				closeHandler: function(e)
28821				{
28822					if (e.which != this.keyCode.ESC) return;
28823
28824					this.dropdown.hideAll();
28825					this.$editor.focus();
28826				},
28827				hideAll: function()
28828				{
28829					this.$toolbar.find('a.dropact').removeClass('redactor-act').removeClass('dropact');
28830
28831					this.utils.enableBodyScroll();
28832
28833					$('.redactor-dropdown-' + this.uuid).hide();
28834					$('.redactor-dropdown-link-selected').removeClass('redactor-dropdown-link-selected');
28835
28836
28837					if (this.$dropdown)
28838					{
28839						this.$dropdown.off('.redactor-dropdown');
28840						this.core.setCallback('dropdownHide', this.$dropdown);
28841
28842						this.$dropdown = false;
28843					}
28844				},
28845				hide: function (e)
28846				{
28847					var $dropdown = $(e.target);
28848
28849					if (!$dropdown.hasClass('dropact') && !$dropdown.hasClass('redactor-dropdown-link-inactive'))
28850					{
28851						if ($dropdown.hasClass('redactor-dropdown'))
28852						{
28853							$dropdown.removeClass('dropact');
28854							$dropdown.off('mouseover mouseout');
28855						}
28856
28857						this.dropdown.hideAll();
28858					}
28859				}
28860			};
28861		},
28862		file: function()
28863		{
28864			return {
28865				show: function()
28866				{
28867					this.modal.load('file', this.lang.get('file'), 700);
28868					this.upload.init('#redactor-modal-file-upload', this.opts.fileUpload, this.file.insert);
28869
28870					this.selection.save();
28871
28872					this.selection.get();
28873					var text = this.sel.toString();
28874
28875					$('#redactor-filename').val(text);
28876
28877					this.modal.show();
28878				},
28879				insert: function(json, direct, e)
28880				{
28881					// error callback
28882					if (typeof json.error != 'undefined')
28883					{
28884						this.modal.close();
28885						this.selection.restore();
28886						this.core.setCallback('fileUploadError', json);
28887						return;
28888					}
28889
28890					var link;
28891					if (typeof json == 'string')
28892					{
28893						link = json;
28894					}
28895					else
28896					{
28897						var text = $('#redactor-filename').val();
28898						if (typeof text == 'undefined' || text === '') text = json.filename;
28899
28900						link = '<a href="' + json.filelink + '" id="filelink-marker">
28900' + text + '</a>';
28901					}
28902
28903					if (direct)
28904					{
28905						this.selection.removeMarkers();
28906						var marker = this.selection.getMarker();
28907						this.insert.nodeToCaretPositionFromPoint(e, marker);
28908					}
28909					else
28910					{
28911						this.modal.close();
28912					}
28913
28914					this.selection.restore();
28915					this.buffer.set();
28916
28917					this.insert.htmlWithoutClean(link);
28918
28919					if (typeof json == 'string') return;
28920
28921					var linkmarker = $(this.$editor.find('a#filelink-marker'));
28922					if (linkmarker.length !== 0)
28923					{
28924						linkmarker.removeAttr('id').removeAttr('style');
28925					}
28926					else linkmarker = false;
28927
28928					this.core.setCallback('fileUpload', linkmarker, json);
28929
28930				}
28931			};
28932		},
28933		focus: function()
28934		{
28935			return {
28936				setStart: function()
28937				{
28938					this.$editor.focus();
28939
28940					var first = this.$editor.children().first();
28941
28942					if (first.length === 0) return;
28943					if (first[0].length === 0 || first[0].tagName == 'BR' || first[0].nodeType == 3)
28944					{
28945						return;
28946					}
28947
28948					if (first[0].tagName == 'UL' || first[0].tagName == 'OL')
28949					{
28950						var child = first.find('li').first();
28951						if (!this.utils.isBlock(child) && child.text() === '')
28952						{
28953							// empty inline tag in li
28954							this.caret.setStart(child);
28955							return;
28956						}
28957					}
28958
28959					if (this.opts.linebreaks && !this.utils.isBlockTag(first[0].tagName))
28960					{
28961						this.selection.get();
28962						this.range.setStart(this.$editor[0], 0);
28963						this.range.setEnd(this.$editor[0], 0);
28964						this.selection.addRange();
28965
28966						return;
28967					}
28968
28969					// if node is tag
28970					this.caret.setStart(first);
28971				},
28972				setEnd: function()
28973				{
28974					var last = this.$editor.children().last();
28975					this.$editor.focus();
28976
28977					if (last.size() === 0) return;
28978					if (this.utils.isEmpty(this.$editor.html()))
28979					{
28980
28981						this.selection.get();
28982						this.range.collapse(true);
28983						this.range.setStartAfter(last[0]);
28984						this.range.setEnd(last[0], 0);
28985						this.selection.addRange();
28986					}
28987					else
28988					{
28989						this.selection.get();
28990						this.range.selectNodeContents(last[0]);
28991						this.range.collapse(false);
28992						this.selection.addRange();
28993
28994					}
28995				},
28996				isFocused: function()
28997				{
28998					return this.$editor[0] === document.activeElement;
28999				}
29000			};
29001		},
29002		image: function()
29003		{
29004			return {
29005				show: function()
29006				{
29007					this.modal.load('image', this.lang.get('image'), 700);
29008					this.upload.init('#redactor-modal-image-droparea', this.opts.imageUpload, this.image.insert);
29009
29010					this.selection.save();
29011					this.modal.show();
29012
29013				},
29014				showEdit: function($image)
29015				{
29016					var $link = $image.closest('a', this.$editor[0]);
29017
29018					this.modal.load('imageEdit', this.lang.get('edit'), 705);
29019
29020					this.modal.createCancelButton();
29021					this.image.buttonDelete = this.modal.createDeleteButton(this.lang.get('_delete'));
29022					this.image.buttonSave = this.modal.createActionButton(this.lang.get('save'));
29023
29024					this.image.buttonDelete.on('click', $.proxy(function()
29025					{
29026						this.image.remove($image);
29027
29028					}, this));
29029
29030					this.image.buttonSave.on('click', $.proxy(function()
29031					{
29032						this.image.update($image);
29033
29034					}, this));
29035
29036					// hide link's tooltip
29037					$('.redactor-link-tooltip').remove();
29038
29039					$('#redactor-image-title').val($image.attr('alt'));
29040
29041					if (!this.opts.imageLink) $('.redactor-image-link-option').hide();
29042					else
29043					{
29044						var $redactorImageLink = $('#redactor-image-link');
29045
29046						$redactorImageLink.attr('href', $image.attr('src'));
29047						if ($link.length !== 0)
29048						{
29049							$redactorImageLink.val($link.attr('href'));
29050							if ($link.attr('target') == '_blank') $('#redactor-image-link-blank').prop('checked', true);
29051						}
29052					}
29053
29054					if (!this.opts.imagePosition) $('.redactor-image-position-option').hide();
29055					else
29056					{
29057						var floatValue = ($image.css('display') == 'block' && $image.css('float') == 'none') ? 'center' : $image.css('float');
29058						$('#redactor-image-align').val(floatValue);
29059					}
29060
29061					this.modal.show();
29062					$('#redactor-image-title').focus();
29063
29064				},
29065				setFloating: function($image)
29066				{
29067					var floating = $('#redactor-image-align').val();
29068
29069					var imageFloat = '';
29070					var imageDisplay = '';
29071					var imageMargin = '';
29072
29073					switch (floating)
29074					{
29075						case 'left':
29076							imageFloat = 'left';
29077							imageMargin = '0 ' + this.opts.imageFloatMargin + ' ' + this.opts.imageFloatMargin + ' 0';
29078						break;
29079						case 'right':
29080							imageFloat = 'right';
29081							imageMargin = '0 0 ' + this.opts.imageFloatMargin + ' ' + this.opts.imageFloatMargin;
29082						break;
29083						case 'center':
29084							imageDisplay = 'block';
29085							imageMargin = 'auto';
29086						break;
29087					}
29088
29089					$image.css({ 'float': imageFloat, display: imageDisplay, margin: imageMargin });
29090					$image.attr('rel', $image.attr('style'));
29091				},
29092				update: function($image)
29093				{
29094					this.image.hideResize();
29095					this.buffer.set();
29096
29097					var $link = $image.closest('a', this.$editor[0]);
29098
29099					var title = $('#redactor-image-title').val().replace(/(<([^>]+)>)/ig,"");
29100					$image.attr('alt', title);
29101
29102					this.image.setFloating($image);
29103
29104					// as link
29105					var link = $.trim($('#redactor-image-link').val());
29106					var link = link.replace(/(<([^>]+)>)/ig,"");
29107					if (link !== '')
29108					{
29109						// test url (add protocol)
29110						var pattern = '((xn--)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,}';
29111						var re = new RegExp('^(http|ftp|https)://' + pattern, 'i');
29112						var re2 = new RegExp('^' + pattern, 'i');
29113
29114						if (link.search(re) == -1 && link.search(re2) === 0 && this.opts.linkProtocol)
29115						{
29116							link = this.opts.linkProtocol + '://' + link;
29117						}
29118
29119						var target = ($('#redactor-image-link-blank').prop('checked')) ? true : false;
29120
29121						if ($link.length === 0)
29122						{
29123							var a = $('<a href="' + link + '">' + this.utils.getOuterHtml($image) + '</a>');
29124							if (target) a.attr('target', '_blank');
29125
29126							$image.replaceWith(a);
29127						}
29128						else
29129						{
29130							$link.attr('href', link);
29131							if (target)
29132							{
29133								$link.attr('target', '_blank');
29134							}
29135							else
29136							{
29137								$link.removeAttr('target');
29138							}
29139						}
29140					}
29141					else if ($link.length !== 0)
29142					{
29143						$link.replaceWith(this.utils.getOuterHtml($image));
29144
29145					}
29146
29147					this.modal.close();
29148					this.observe.images();
29149					this.code.sync();
29150
29151
29152				},
29153				setEditable: function($image)
29154				{
29155					if (this.opts.imageEditable)
29156					{
29157						$image.on('dragstart', $.proxy(this.image.onDrag, this));
29158					}
29159
29160					var handler = $.proxy(function(e)
29161					{
29162
29163						this.observe.image = $image;
29164
29165						this.image.resizer = this.image.loadEditableControls($image);
29166
29167						$(document).on('mousedown.redactor-image-resize-hide.' + this.uuid, $.proxy(this.image.hideResize, this));
29168
29169						// resize
29170						if (!this.opts.imageResizable) return;
29171
29172						this.image.resizer.on('mousedown.redactor touchstart.redactor', $.proxy(function(e)
29173						{
29174							this.image.setResizable(e, $image);
29175						}, this));
29176
29177					}, this);
29178
29179
29180					$image.off('mousedown.redactor').on('mousedown.redactor', $.proxy(this.image.hideResize, this));
29181					$image.off('click.redactor touchstart.redactor').on('click.redactor touchstart.redactor', handler);
29182				},
29183				setResizable: function(e, $image)
29184				{
29185					e.preventDefault();
29186
29187				    this.image.resizeHandle = {
29188				        x : e.pageX,
29189				        y : e.pageY,
29190				        el : $image,
29191				        ratio: $image.width() / $image.height(),
29192				        h: $image.height()
29193				    };
29194
29195				    e = e.originalEvent || e;
29196
29197				    if (e.targetTouches)
29198				    {
29199				         this.image.resizeHandle.x = e.targetTouches[0].pageX;
29200				         this.image.resizeHandle.y = e.targetTouches[0].pageY;
29201				    }
29202
29203					this.image.startResize();
29204
29205
29206				},
29207				startResize: function()
29208				{
29209					$(document).on('mousemove.redactor-image-resize touchmove.redactor-image-resize', $.proxy(this.image.moveResize, this));
29210					$(document).on('mouseup.redactor-image-resize touchend.redactor-image-resize', $.proxy(this.image.stopResize, this));
29211				},
29212				moveResize: function(e)
29213				{
29214					e.preventDefault();
29215
29216					e = e.originalEvent || e;
29217
29218					var height = this.image.resizeHandle.h;
29219
29220		            if (e.targetTouches) height += (e.targetTouches[0].pageY -  this.image.resizeHandle.y);
29221		            else height += (e.pageY -  this.image.resizeHandle.y);
29222
29223					var width = Math.round(height * this.image.resizeHandle.ratio);
29224
29225					if (height < 50 || width < 100) return;
29226
29227					var height = Math.round(this.image.resizeHandle.el.width() / this.image.resizeHandle.ratio);
29228
29229					this.image.resizeHandle.el.attr({width: width, height: height});
29230		            this.image.resizeHandle.el.width(width);
29231		            this.image.resizeHandle.el.height(height);
29232
29233		            this.code.sync();
29234				},
29235				stopResize: function()
29236				{
29237					this.handle = false;
29238					$(document).off('.redactor-image-resize');
29239
29240					this.image.hideResize();
29241				},
29242				onDrag: function(e)
29243				{
29244					if (this.$editor.find('#redactor-image-box').length !== 0)
29245					{
29246						e.preventDefault();
29247						return false;
29248					}
29249
29250					this.$editor.on('drop.redactor-image-inside-drop', $.proxy(function()
29251					{
29252						setTimeout($.proxy(this.image.onDrop, this), 1);
29253
29254					}, this));
29255				},
29256				onDrop: function()
29257				{
29258					this.image.fixImageSourceAfterDrop();
29259					this.observe.images();
29260					this.$editor.off('drop.redactor-image-inside-drop');
29261					this.clean.clearUnverified();
29262					this.code.sync();
29263				},
29264				fixImageSourceAfterDrop: function()
29265				{
29266					this.$editor.find('img[data-save-url]').each(function()
29267					{
29268						var $el = $(this);
29269						$el.attr('src', $el.attr('data-save-url'));
29270						$el.removeAttr('data-save-url');
29271					});
29272				},
29273				hideResize: function(e)
29274				{
29275					if (e && $(e.target).closest('#redactor-image-box', this.$editor[0]).length !== 0) return;
29276					if (e && e.target.tagName == 'IMG')
29277					{
29278						var $image = $(e.target);
29279						$image.attr('data-save-url', $image.attr('src'));
29280					}
29281
29282					var imageBox = this.$editor.find('#redactor-image-box');
29283					if (imageBox.length === 0) return;
29284
29285					$('#redactor-image-editter').remove();
29286					$('#redactor-image-resizer').remove();
29287
29288					imageBox.find('img').css({
29289						marginTop: imageBox[0].style.marginTop,
29290						marginBottom: imageBox[0].style.marginBottom,
29291						marginLeft: imageBox[0].style.marginLeft,
29292						marginRight: imageBox[0].style.marginRight
29293					});
29294
29295					imageBox.css('margin', '');
29296					imageBox.find('img').css('opacity', '');
29297					imageBox.replaceWith(function()
29298					{
29299						return $(this).contents();
29300					});
29301
29302					$(document).off('mousedown.redactor-image-resize-hide.' + this.uuid);
29303
29304
29305					if (typeof this.image.resizeHandle !== 'undefined')
29306					{
29307						this.image.resizeHandle.el.attr('rel', this.image.resizeHandle.el.attr('style'));
29308					}
29309
29310					this.code.sync();
29311
29312				},
29313				loadResizableControls: function($image, imageBox)
29314				{
29315					if (this.opts.imageResizable && !this.utils.isMobile())
29316					{
29317						var imageResizer = $('<span id="redactor-image-resizer" data-redactor="verified"></span>');
29318
29319						if (!this.utils.isDesktop())
29320						{
29321							imageResizer.css({ width: '15px', height: '15px' });
29322						}
29323
29324						imageResizer.attr('contenteditable', false);
29325						imageBox.append(imageResizer);
29326						imageBox.append($image);
29327
29328						return imageResizer;
29329					}
29330					else
29331					{
29332						imageBox.append($image);
29333						return false;
29334					}
29335				},
29336				loadEditableControls: function($image)
29337				{
29338					var imageBox = $('<span id="redactor-image-box" data-redactor="verified">');
29339					imageBox.css('float', $image.css('float')).attr('contenteditable', false);
29340
29341					if ($image[0].style.margin != 'auto')
29342					{
29343						imageBox.css({
29344							marginTop: $image[0].style.marginTop,
29345							marginBottom: $image[0].style.marginBottom,
29346							marginLeft: $image[0].style.marginLeft,
29347							marginRight: $image[0].style.marginRight
29348						});
29349
29350						$image.css('margin', '');
29351					}
29352					else
29353					{
29354						imageBox.css({ 'display': 'block', 'margin': 'auto' });
29355					}
29356
29357					$image.css('opacity', '.5').after(imageBox);
29358
29359
29360					if (this.opts.imageEditable)
29361					{
29362						// editter
29363						this.image.editter = $('<span id="redactor-image-editter" data-redactor="verified">' + this.lang.get('edit') + '</span>');
29364						this.image.editter.attr('contenteditable', false);
29365						this.image.editter.on('click', $.proxy(function()
29366						{
29367							this.image.showEdit($image);
29368						}, this));
29369
29370						imageBox.append(this.image.editter);
29371
29372						// position correction
29373						var editerWidth = this.image.editter.innerWidth();
29374						this.image.editter.css('margin-left', '-' + editerWidth/2 + 'px');
29375					}
29376
29377					return this.image.loadResizableControls($image, imageBox);
29378
29379				},
29380				remove: function(image)
29381				{
29382					var $image = $(image);
29383					var $link = $image.closest('a', this.$editor[0]);
29384					var $figure = $image.closest('figure', this.$editor[0]);
29385					var $parent = $image.parent();
29386					if ($('#redactor-image-box').length !== 0)
29387					{
29388						$parent = $('#redactor-image-box').parent();
29389					}
29390
29391					var $next;
29392					if ($figure.length !== 0)
29393					{
29394						$next = $figure.next();
29395						$figure.remove();
29396					}
29397					else if ($link.length !== 0)
29398					{
29399						$parent = $link.parent();
29400						$link.remove();
29401					}
29402					else
29403					{
29404						$image.remove();
29405					}
29406
29407					$('#redactor-image-box').remove();
29408
29409					if ($figure.length !== 0)
29410					{
29411						this.caret.setStart($next);
29412					}
29413					else
29414					{
29415						this.caret.setStart($parent);
29416					}
29417
29418					// delete callback
29419					this.core.setCallback('imageDelete', $image[0].src, $image);
29420
29421					this.modal.close();
29422					this.code.sync();
29423				},
29424				insert: function(json, direct, e)
29425				{
29426					// error callback
29427					if (typeof json.error != 'undefined')
29428					{
29429						this.modal.close();
29430						this.selection.restore();
29431						this.core.setCallback('imageUploadError', json);
29432						return;
29433					}
29434
29435					var $img;
29436					if (typeof json == 'string')
29437					{
29438						$img = $(json).attr('data-redactor-inserted-image', 'true');
29439					}
29440					else
29441					{
29442						$img = $('<img>');
29443						$img.attr('src', json.filelink).attr('data-redactor-inserted-image', 'true');
29444					}
29445
29446
29447					var node = $img;
29448					var isP = this.utils.isCurrentOrParent('P');
29449					if (isP)
29450					{
29451						// will replace
29452						node = $('<blockquote />').append($img);
29453					}
29454
29455					if (direct)
29456					{
29457						this.selection.removeMarkers();
29458						var marker = this.selection.getMarker();
29459						this.insert.nodeToCaretPositionFromPoint(e, marker);
29460					}
29461					else
29462					{
29463						this.modal.close();
29464					}
29465
29466					this.selection.restore();
29467					this.buffer.set();
29468
29469					this.insert.html(this.utils.getOuterHtml(node), false);
29470
29471					var $image = this.$editor.find('img[data-redactor-inserted-image=true]').removeAttr('data-redactor-inserted-image');
29472
29473					if (isP)
29474					{
29475						$image.parent().contents().unwrap().wrap('<p />');
29476					}
29477					else if (this.opts.linebreaks)
29478					{
29479						if (!this.utils.isEmpty(this.code.get()))
29480						{
29481							$image.before('<br>');
29482						}
29483
29484						$image.after('<br>');
29485					}
29486
29487					if (typeof json == 'string') return;
29488
29489					this.core.setCallback('imageUpload', $image, json);
29490
29491				}
29492			};
29493		},
29494		indent: function()
29495		{
29496			return {
29497				increase: function()
29498				{
29499					// focus
29500					if (!this.utils.browser('msie')) this.$editor.focus();
29501
29502					this.buffer.set();
29503					this.selection.save();
29504
29505					var block = this.selection.getBlock();
29506
29507					if (block && block.tagName == 'LI')
29508					{
29509						this.indent.increaseLists();
29510					}
29511					else if (block === false && this.opts.linebreaks)
29512					{
29513						this.indent.increaseText();
29514					}
29515					else
29516					{
29517						this.indent.increaseBlocks();
29518					}
29519
29520					this.selection.restore();
29521					this.code.sync();
29522				},
29523				increaseLists: function()
29524				{
29525					document.execCommand('indent');
29526
29527					this.indent.fixEmptyIndent();
29528					this.clean.normalizeLists();
29529					this.clean.clearUnverified();
29530				},
29531				increaseBlocks: function()
29532				{
29533					$.each(this.selection.getBlocks(), $.proxy(function(i, elem)
29534					{
29535						if (elem.tagName === 'TD' || elem.tagName === 'TH') return;
29536
29537						var $el = this.utils.getAlignmentElement(elem);
29538
29539						var left = this.utils.normalize($el.css('margin-left')) + this.opts.indentValue;
29540						$el.css('margin-left', left + 'px');
29541
29542					}, this));
29543				},
29544				increaseText: function()
29545				{
29546					var wrapper = this.selection.wrap('div');
29547					$(wrapper).attr('data-tagblock', 'redactor');
29548					$(wrapper).css('margin-left', this.opts.indentValue + 'px');
29549				},
29550				decrease: function()
29551				{
29552					this.buffer.set();
29553					this.selection.save();
29554
29555					var block = this.selection.getBlock();
29556					if (block && block.tagName == 'LI')
29557					{
29558						this.indent.decreaseLists();
29559					}
29560					else
29561					{
29562						this.indent.decreaseBlocks();
29563					}
29564
29565					this.selection.restore();
29566					this.code.sync();
29567				},
29568				decreaseLists: function()
29569				{
29570					document.execCommand('outdent');
29571
29572					var current = this.selection.getCurrent();
29573					var $item = $(current).closest('li', this.$editor[0]);
29574
29575					this.indent.fixEmptyIndent();
29576
29577					if (!this.opts.linebreaks && $item.length === 0)
29578					{
29579						document.execCommand('formatblock', false, 'p');
29580						this.$editor.find('ul, ol, blockquote, p').each($.proxy(this.utils.removeEmpty, this));
29581					}
29582
29583					this.clean.clearUnverified();
29584				},
29585				decreaseBlocks: function()
29586				{
29587					$.each(this.selection.getBlocks(), $.proxy(function(i, elem)
29588					{
29589						var $el = this.utils.getAlignmentElement(elem);
29590						var left = this.utils.normalize($el.css('margin-left')) - this.opts.indentValue;
29591
29592						if (left <= 0)
29593						{
29594							if (this.opts.linebreaks && typeof($el.data('tagblock')) !== 'undefined')
29595							{
29596								$el.replaceWith($el.html() + '<br />');
29597							}
29598							else
29599							{
29600								$el.css('margin-left', '');
29601								this.utils.removeEmptyAttr($el, 'style');
29602							}
29603						}
29604						else
29605						{
29606							$el.css('margin-left', left + 'px');
29607						}
29608
29609					}, this));
29610				},
29611				fixEmptyIndent: function()
29612				{
29613					var block = this.selection.getBlock();
29614
29615					if (this.range.collapsed && block && block.tagName == 'LI' && this.utils.isEmpty($(block).text()))
29616					{
29617						var $block = $(block);
29618						$block.find('span').not('.redactor-selection-marker').contents().unwrap();
29619						$block.append('<br>');
29620					}
29621				}
29622			};
29623		},
29624		inline: function()
29625		{
29626			return {
29627				formatting: function(name)
29628				{
29629					var type, value;
29630
29631					if (typeof this.formatting[name].style != 'undefined') type = 'style';
29632					else if (typeof this.formatting[name]['class'] != 'undefined') type = 'class';
29633
29634					if (type) value = this.formatting[name][type];
29635
29636					this.inline.format(this.formatting[name].tag, type, value);
29637
29638				},
29639				format: function(tag, type, value)
29640				{
29641					var current = this.selection.getCurrent();
29642					if (current && current.tagName === 'TR') return;
29643
29644					// Stop formatting pre and headers
29645					if (this.utils.isCurrentOrParent('PRE') || this.utils.isCurrentOrParentHeader()) return;
29646
29647					var tags = ['b', 'bold', 'i', 'italic', 'underline', 'strikethrough', 'deleted', 'superscript', 'subscript'];
29648					var replaced = ['strong', 'strong', 'em', 'em', 'u', 'del', 'del', 'sup', 'sub'];
29649
29650					for (var i = 0; i < tags.length; i++)
29651					{
29652						if (tag == tags[i]) tag = replaced[i];
29653					}
29654
29655
29656					if (this.opts.allowedTags)
29657					{
29658						if ($.inArray(tag, this.opts.allowedTags) == -1) return;
29659					}
29660					else
29661					{
29662						if ($.inArray(tag, this.opts.deniedTags) !== -1) return;
29663					}
29664
29665					this.inline.type = type || false;
29666					this.inline.value = value || false;
29667
29668					this.buffer.set();
29669
29670					if (!this.utils.browser('msie') && !this.opts.linebreaks)
29671					{
29672						this.$editor.focus();
29673					}
29674
29675					this.selection.get();
29676
29677					if (this.range.collapsed)
29678					{
29679						this.inline.formatCollapsed(tag);
29680					}
29681					else
29682					{
29683						this.inline.formatMultiple(tag);
29684					}
29685				},
29686				formatCollapsed: function(tag)
29687				{
29688					var current = this.selection.getCurrent();
29689					var $parent = $(current).closest(tag + '[data-redactor-tag=' + tag + ']', this.$editor[0]);
29690
29691					// inline there is
29692					if ($parent.length !== 0 && (this.inline.type != 'style' && $parent[0].tagName != 'SPAN'))
29693					{
29694						// remove empty
29695						if (this.utils.isEmpty($parent.text()))
29696						{
29697							this.caret.setAfter($parent[0]);
29698
29699							$parent.remove();
29700							this.code.sync();
29701						}
29702						else if (this.utils.isEndOfElement($parent))
29703						{
29704							this.caret.setAfter($parent[0]);
29705						}
29706
29707						return;
29708					}
29709
29710					// create empty inline
29711					var node = $('<' + tag + '>').attr('data-verified', 'redactor').attr('data-redactor-tag', tag);
29712					node.html(this.opts.invisibleSpace);
29713
29714					node = this.inline.setFormat(node);
29715
29716					var node = this.insert.node(node);
29717					this.caret.setEnd(node);
29718
29719					this.code.sync();
29720				},
29721				formatMultiple: function(tag)
29722				{
29723					this.inline.formatConvert(tag);
29724
29725					this.selection.save();
29726					document.execCommand('strikethrough');
29727
29728					this.$editor.find('strike').each($.proxy(function(i,s)
29729					{
29730						var $el = $(s);
29731
29732						this.inline.formatRemoveSameChildren($el, tag);
29733
29734						var $span;
29735						if (this.inline.type)
29736						{
29737							$span = $('<span>').attr('data-redactor-tag', tag).attr('data-verified', 'redactor');
29738							$span = this.inline.setFormat($span);
29739						}
29740						else
29741						{
29742							$span = $('<' + tag + '>').attr('data-redactor-tag', tag).attr('data-verified', 'redactor');
29743						}
29744
29745						$el.replaceWith($span.html($el.contents()));
29746						var $parent = $span.parent();
29747
29748						// remove U tag if selected link + node
29749						if ($span[0].tagName === 'A' && $parent && $parent[0].tagName === 'U')
29750						{
29751							$span.parent().replaceWith($span);
29752						}
29753
29754						if (tag == 'span')
29755						{
29756							if ($parent && $parent[0].tagName === 'SPAN' && this.inline.type === 'style')
29757							{
29758								var arr = this.inline.value.split(';');
29759
29760								for (var z = 0; z < arr.length; z++)
29761								{
29762									if (arr[z] === '') return;
29763									var style = arr[z].split(':');
29764									$parent.css(style[0], '');
29765
29766									if (this.utils.removeEmptyAttr($parent, 'style'))
29767									{
29768										$parent.replaceWith($parent.contents());
29769									}
29770
29771								}
29772
29773							}
29774						}
29775
29776					}, this));
29777
29778					// clear text decoration
29779					if (tag != 'span')
29780					{
29781						this.$editor.find(this.opts.inlineTags.join(', ')).each($.proxy(function(i,s)
29782						{
29783							var $el = $(s);
29784
29785
29786							if (s.tagName === 'U' && s.attributes.length === 0)
29787							{
29788								$el.replaceWith($el.contents());
29789								return;
29790							}
29791
29792							var property = $el.css('text-decoration');
29793							if (property === 'line-through')
29794							{
29795								$el.css('text-decoration', '');
29796								this.utils.removeEmptyAttr($el, 'style');
29797							}
29798						}, this));
29799					}
29800
29801					if (tag != 'del')
29802					{
29803						var _this = this;
29804						this.$editor.find('inline').each(function(i,s)
29805						{
29806							_this.utils.replaceToTag(s, 'del');
29807						});
29808					}
29809
29810					if (tag != 'u')
29811					{
29812						var _this = this;
29813						this.$editor.find('unline').each(function(i,s)
29814						{
29815							_this.utils.replaceToTag(s, 'u');
29816						});
29817					}
29818
29819					this.selection.restore();
29820					this.code.sync();
29821
29822				},
29823				formatRemoveSameChildren: function($el, tag)
29824				{
29825					var self = this;
29826					$el.children(tag).each(function()
29827					{
29828						var $child = $(this);
29829
29830						if (!$child.hasClass('redactor-selection-marker'))
29831						{
29832							if (self.inline.type == 'style')
29833							{
29834								var arr = self.inline.value.split(';');
29835
29836								for (var z = 0; z < arr.length; z++)
29837								{
29838									if (arr[z] === '') return;
29839
29840									var style = arr[z].split(':');
29841									$child.css(style[0], '');
29842
29843									if (self.utils.removeEmptyAttr($child , 'style'))
29844									{
29845										$child.replaceWith($child.contents());
29846									}
29847
29848								}
29849							}
29850							else
29851							{
29852								$child.contents().unwrap();
29853							}
29854						}
29855
29856					});
29857				},
29858				formatConvert: function(tag)
29859				{
29860					this.selection.save();
29861
29862					var find = '';
29863					if (this.inline.type == 'class') find = '[data-redactor-class=' + this.inline.value + ']';
29864					else if (this.inline.type == 'style')
29865					{
29866						find = '[data-redactor-style="' + this.inline.value + '"]';
29867					}
29868
29869					var self = this;
29870					if (tag != 'del')
29871					{
29872						this.$editor.find('del').each(function(i,s)
29873						{
29874							self.utils.replaceToTag(s, 'inline');
29875						});
29876					}
29877
29878					if (tag != 'u')
29879					{
29880						this.$editor.find('u').each(function(i,s)
29881						{
29882							self.utils.replaceToTag(s, 'unline');
29883						});
29884					}
29885
29886					if (tag != 'span')
29887					{
29888						this.$editor.find(tag).each(function()
29889						{
29890							var $el = $(this);
29891							$el.replaceWith($('<strike />').html($el.contents()));
29892
29893						});
29894					}
29895
29896					this.$editor.find('[data-redactor-tag="' + tag + '"]' + find).each(function()
29897					{
29898						if (find === '' && tag == 'span' && this.tagName.toLowerCase() == tag) return;
29899
29900						var $el = $(this);
29901						$el.replaceWith($('<strike />').html($el.contents()));
29902
29903					});
29904
29905					this.selection.restore();
29906				},
29907				setFormat: function(node)
29908				{
29909					switch (this.inline.type)
29910					{
29911						case 'class':
29912
29913							if (node.hasClass(this.inline.value))
29914							{
29915								node.removeClass(this.inline.value);
29916								node.removeAttr('data-redactor-class');
29917							}
29918							else
29919							{
29920								node.addClass(this.inline.value);
29921								node.attr('data-redactor-class', this.inline.value);
29922							}
29923
29924
29925						break;
29926						case 'style':
29927
29928							node[0].style.cssText = this.inline.value;
29929							node.attr('data-redactor-style', this.inline.value);
29930
29931						break;
29932					}
29933
29934					return node;
29935				},
29936				removeStyle: function()
29937				{
29938					this.buffer.set();
29939					var current = this.selection.getCurrent();
29940					var nodes = this.selection.getInlines();
29941
29942					this.selection.save();
29943
29944					if (current && current.tagName === 'SPAN')
29945					{
29946						var $s = $(current);
29947
29948						$s.removeAttr('style');
29949						if ($s[0].attributes.length === 0)
29950						{
29951							$s.replaceWith($s.contents());
29952						}
29953					}
29954
29955					$.each(nodes, $.proxy(function(i,s)
29956					{
29957						var $s = $(s);
29958						if ($.inArray(s.tagName.toLowerCase(), this.opts.inlineTags) != -1 && !$s.hasClass('redactor-selection-marker'))
29959						{
29960							$s.removeAttr('style');
29961							if ($s[0].attributes.length === 0)
29962							{
29963								$s.replaceWith($s.contents());
29964							}
29965						}
29966					}, this));
29967
29968					this.selection.restore();
29969					this.code.sync();
29970
29971				},
29972				removeStyleRule: function(name)
29973				{
29974					this.buffer.set();
29975					var parent = this.selection.getParent();
29976					var nodes = this.selection.getInlines();
29977
29978					this.selection.save();
29979
29980					if (parent && parent.tagName === 'SPAN')
29981					{
29982						var $s = $(parent);
29983
29984						$s.css(name, '');
29985						this.utils.removeEmptyAttr($s, 'style');
29986						if ($s[0].attributes.length === 0)
29987						{
29988							$s.replaceWith($s.contents());
29989						}
29990					}
29991
29992					$.each(nodes, $.proxy(function(i,s)
29993					{
29994						var $s = $(s);
29995						if ($.inArray(s.tagName.toLowerCase(), this.opts.inlineTags) != -1 && !$s.hasClass('redactor-selection-marker'))
29996						{
29997							$s.css(name, '');
29998							this.utils.removeEmptyAttr($s, 'style');
29999							if ($s[0].attributes.length === 0)
30000							{
30001								$s.replaceWith($s.contents());
30002							}
30003						}
30004					}, this));
30005
30006					this.selection.restore();
30007					this.code.sync();
30008				},
30009				removeFormat: function()
30010				{
30011					this.buffer.set();
30012					var current = this.selection.getCurrent();
30013
30014					this.selection.save();
30015
30016					document.execCommand('removeFormat');
30017
30018					if (current && current.tagName === 'SPAN')
30019					{
30020						$(current).replaceWith($(current).contents());
30021					}
30022
30023
30024					$.each(this.selection.getNodes(), $.proxy(function(i,s)
30025					{
30026						var $s = $(s);
30027						if ($.inArray(s.tagName.toLowerCase(), this.opts.inlineTags) != -1 && !$s.hasClass('redactor-selection-marker'))
30028						{
30029							$s.replaceWith($s.contents());
30030						}
30031					}, this));
30032
30033					this.selection.restore();
30034					this.code.sync();
30035
30036				},
30037				toggleClass: function(className)
30038				{
30039					this.inline.format('span', 'class', className);
30040				},
30041				toggleStyle: function(value)
30042				{
30043					this.inline.format('span', 'style', value);
30044				}
30045			};
30046		},
30047		insert: function()
30048		{
30049			return {
30050				set: function(html, clean)
30051				{
30052					this.placeholder.remove();
30053
30054					html = this.clean.setVerified(html);
30055
30056					if (typeof clean == 'undefined')
30057					{
30058						html = this.clean.onPaste(html, false);
30059					}
30060
30061					this.$editor.html(html);
30062					this.selection.remove();
30063					this.focus.setEnd();
30064					this.clean.normalizeLists();
30065					this.code.sync();
30066					this.observe.load();
30067
30068					if (typeof clean == 'undefined')
30069					{
30070						setTimeout($.proxy(this.clean.clearUnverified, this), 10);
30071					}
30072				},
30073				text: function(text)
30074				{
30075					this.placeholder.remove();
30076
30077					text = text.toString();
30078					text = $.trim(text);
30079					text = this.clean.getPlainText(text, false);
30080
30081					this.$editor.focus();
30082
30083					if (this.utils.browser('msie'))
30084					{
30085						this.insert.htmlIe(text);
30086					}
30087					else
30088					{
30089						this.selection.get();
30090
30091						this.range.deleteContents();
30092						var el = document.createElement("div");
30093						el.innerHTML = text;
30094						var frag = document.createDocumentFragment(), node, lastNode;
30095						while ((node = el.firstChild))
30096						{
30097							lastNode = frag.appendChild(node);
30098						}
30099
30100						this.range.insertNode(frag);
30101
30102						if (lastNode)
30103						{
30104							var range = this.range.cloneRange();
30105							range.setStartAfter(lastNode);
30106							range.collapse(true);
30107							this.sel.removeAllRanges();
30108							this.sel.addRange(range);
30109						}
30110					}
30111
30112					this.code.sync();
30113					this.clean.clearUnverified();
30114				},
30115				htmlWithoutClean: function(html)
30116				{
30117					this.insert.html(html, false);
30118				},
30119				html: function(html, clean)
30120				{
30121					this.placeholder.remove();
30122
30123					if (typeof clean == 'undefined') clean = true;
30124
30125					if (!this.opts.linebreaks)
30126					{
30127						this.$editor.focus();
30128					}
30129
30130					html = this.clean.setVerified(html);
30131
30132					if (clean)
30133					{
30134						html = this.clean.onPaste(html);
30135					}
30136
30137					if (this.utils.browser('msie'))
30138					{
30139						this.insert.htmlIe(html);
30140					}
30141					else
30142					{
30143						if (this.clean.singleLine) this.insert.execHtml(html);
30144						else document.execCommand('insertHTML', false, html);
30145
30146						this.insert.htmlFixMozilla();
30147
30148					}
30149
30150					this.clean.normalizeLists();
30151
30152					// remove empty paragraphs finaly
30153					if (!this.opts.linebreaks)
30154					{
30155						this.$editor.find('p').each($.proxy(this.utils.removeEmpty, this));
30156					}
30157
30158					this.code.sync();
30159					this.observe.load();
30160
30161					if (clean)
30162					{
30163						this.clean.clearUnverified();
30164					}
30165
30166				},
30167				htmlFixMozilla: function()
30168				{
30169					// FF inserts empty p when content was selected dblclick
30170					if (!this.utils.browser('mozilla')) return;
30171
30172					var $next = $(this.selection.getBlock()).next();
30173					if ($next.length > 0 && $next[0].tagName == 'P' && $next.html() === '')
30174					{
30175						$next.remove();
30176					}
30177
30178				},
30179				htmlIe: function(html)
30180				{
30181					if (this.utils.isIe11())
30182					{
30183						var parent = this.utils.isCurrentOrParent('P');
30184						var $html = $('<div>').append(html);
30185						var blocksMatch = $html.contents().is('p, :header, dl, ul, ol, div, table, td, blockquote, pre, address, section, header, footer, aside, article');
30186
30187						if (parent && blocksMatch) this.insert.ie11FixInserting(parent, html);
30188						else this.insert.ie11PasteFrag(html);
30189
30190						return;
30191					}
30192
30193					document.selection.createRange().pasteHTML(html);
30194
30195				},
30196				execHtml: function(html)
30197				{
30198					html = this.clean.setVerified(html);
30199
30200					this.selection.get();
30201
30202					this.range.deleteContents();
30203
30204					var el = document.createElement('div');
30205					el.innerHTML = html;
30206
30207					var frag = document.createDocumentFragment(), node, lastNode;
30208					while ((node = el.firstChild))
30209					{
30210						lastNode = frag.appendChild(node);
30211					}
30212
30213					this.range.insertNode(frag);
30214
30215					this.range.collapse(true);
30216					this.caret.setAfter(lastNode);
30217
30218				},
30219				node: function(node, deleteContents)
30220				{
30221					node = node[0] || node;
30222
30223					var offset = this.caret.getOffset();
30224					var html = this.utils.getOuterHtml(node);
30225					html = this.clean.setVerified(html);
30226
30227					if (html.match(/</g) !== null)
30228					{
30229						node = $(html)[0];
30230					}
30231
30232					this.selection.get();
30233
30234					if (deleteContents !== false)
30235					{
30236						this.range.deleteContents();
30237					}
30238
30239					this.range.insertNode(node);
30240					this.range.collapse(false);
30241					this.selection.addRange();
30242
30243					this.caret.setOffset(offset);
30244
30245					return node;
30246				},
30247				nodeToPoint: function(node, x, y)
30248				{
30249					node = node[0] || node;
30250
30251					this.selection.get();
30252
30253					var range;
30254					if (document.caretPositionFromPoint)
30255					{
30256					    var pos = document.caretPositionFromPoint(x, y);
30257
30258					    this.range.setStart(pos.offsetNode, pos.offset);
30259					    this.range.collapse(true);
30260					    this.range.insertNode(node);
30261					}
30262					else if (document.caretRangeFromPoint)
30263					{
30264					    range = document.caretRangeFromPoint(x, y);
30265					    range.insertNode(node);
30266					}
30267					else if (typeof document.body.createTextRange != "undefined")
30268					{
30269				        range = document.body.createTextRange();
30270				        range.moveToPoint(x, y);
30271				        var endRange = range.duplicate();
30272				        endRange.moveToPoint(x, y);
30273				        range.setEndPoint("EndToEnd", endRange);
30274				        range.select();
30275					}
30276				},
30277				nodeToCaretPositionFromPoint: function(e, node)
30278				{
30279					node = node[0] || node;
30280
30281					var range;
30282					var x = e.clientX, y = e.clientY;
30283					if (document.caretPositionFromPoint)
30284					{
30285					    var pos = document.caretPositionFromPoint(x, y);
30286					    var sel = document.getSelection();
30287					    range = sel.getRangeAt(0);
30288					    range.setStart(pos.offsetNode, pos.offset);
30289					    range.collapse(true);
30290					    range.insertNode(node);
30291					}
30292					else if (document.caretRangeFromPoint)
30293					{
30294					    range = document.caretRangeFromPoint(x, y);
30295					    range.insertNode(node);
30296					}
30297					else if (typeof document.body.createTextRange != "undefined")
30298					{
30299				        range = document.body.createTextRange();
30300				        range.moveToPoint(x, y);
30301				        var endRange = range.duplicate();
30302				        endRange.moveToPoint(x, y);
30303				        range.setEndPoint("EndToEnd", endRange);
30304				        range.select();
30305					}
30306
30307				},
30308				ie11FixInserting: function(parent, html)
30309				{
30310					var node = document.createElement('span');
30311					node.className = 'redactor-ie-paste';
30312					this.insert.node(node);
30313
30314					var parHtml = $(parent).html();
30315
30316					parHtml = '<p>' + parHtml.replace(/<span class="redactor-ie-paste"><\/span>/gi, '</p>' + html + '<p>') + '</p>';
30317					parHtml = parHtml.replace(/<p><\/p>/gi, '');
30318					$(parent).replaceWith(parHtml);
30319				},
30320				ie11PasteFrag: function(html)
30321				{
30322					this.selection.get();
30323					this.range.deleteContents();
30324
30325					var el = document.createElement("div");
30326					el.innerHTML = html;
30327
30328					var frag = document.createDocumentFragment(), node, lastNode;
30329					while ((node = el.firstChild))
30330					{
30331						lastNode = frag.appendChild(node);
30332					}
30333
30334					this.range.insertNode(frag);
30335					this.range.collapse(false);
30336					this.selection.addRange();
30337				}
30338			};
30339		},
30340		keydown: function()
30341		{
30342			return {
30343				init: function(e)
30344				{
30345					if (this.rtePaste) return;
30346
30347					var key = e.which;
30348					var arrow = (key >= 37 && key <= 40);
30349
30350					this.keydown.ctrl = e.ctrlKey || e.metaKey;
30351					this.keydown.current = this.selection.getCurrent();
30352					this.keydown.parent = this.selection.getParent();
30353					this.keydown.block = this.selection.getBlock();
30354
30355			        // detect tags
30356					this.keydown.pre = this.utils.isTag(this.keydown.current, 'pre');
30357					this.keydown.blockquote = this.utils.isTag(this.keydown.current, 'blockquote');
30358					this.keydown.figcaption = this.utils.isTag(this.keydown.current, 'figcaption');
30359
30360					// shortcuts setup
30361					this.shortcuts.init(e, key);
30362
30363					if (this.utils.isDesktop())
30364					{
30365						this.keydown.checkEvents(arrow, key);
30366						this.keydown.setupBuffer(e, key);
30367					}
30368
30369					this.keydown.addArrowsEvent(arrow);
30370					this.keydown.setupSelectAll(e, key);
30371
30372					// callback
30373					var keydownStop = this.core.setCallback('keydown', e);
30374					if (keydownStop === false)
30375					{
30376						e.preventDefault();
30377						return false;
30378					}
30379
30380					// ie and ff exit from table
30381					if (this.opts.enterKey && (this.utils.browser('msie') || this.utils.browser('mozilla')) && (key === this.keyCode.DOWN || key === this.keyCode.RIGHT))
30382					{
30383						var isEndOfTable = false;
30384						var $table = false;
30385						if (this.keydown.block && this.keydown.block.tagName === 'TD')
30386						{
30387							$table = $(this.keydown.block).closest('table', this.$editor[0]);
30388						}
30389
30390						if ($table && $table.find('td').last()[0] === this.keydown.block)
30391						{
30392							isEndOfTable = true;
30393						}
30394
30395						if (this.utils.isEndOfElement() && isEndOfTable)
30396						{
30397							var node = $(this.opts.emptyHtml);
30398							$table.after(node);
30399							this.caret.setStart(node);
30400						}
30401					}
30402
30403					// down
30404					if (this.opts.enterKey && key === this.keyCode.DOWN)
30405					{
30406						this.keydown.onArrowDown();
30407					}
30408
30409					// turn off enter key
30410					if (!this.opts.enterKey && key === this.keyCode.ENTER)
30411					{
30412						e.preventDefault();
30413						// remove selected
30414						if (!this.range.collapsed) this.range.deleteContents();
30415						return;
30416					}
30417
30418					// on enter
30419					if (key == this.keyCode.ENTER && !e.shiftKey && !e.ctrlKey && !e.metaKey)
30420					{
30421						var stop = this.core.setCallback('enter', e);
30422						if (stop === false)
30423						{
30424							e.preventDefault();
30425							return false;
30426						}
30427
30428						if (this.keydown.blockquote && this.keydown.exitFromBlockquote(e) === true)
30429						{
30430							return false;
30431						}
30432
30433						var current, $next;
30434						if (this.keydown.pre)
30435						{
30436							return this.keydown.insertNewLine(e);
30437						}
30438						else if (this.keydown.blockquote || this.keydown.figcaption)
30439						{
30440							current = this.selection.getCurrent();
30441							$next = $(current).next();
30442
30443							if ($next.length !== 0 && $next[0].tagName == 'BR')
30444							{
30445								return this.keydown.insertBreakLine(e);
30446							}
30447							else if (this.utils.isEndOfElement() && (current && current != 'SPAN'))
30448							{
30449								return this.keydown.insertDblBreakLine(e);
30450							}
30451							else
30452							{
30453								return this.keydown.insertBreakLine(e);
30454							}
30455						}
30456						else if (this.opts.linebreaks && !this.keydown.block)
30457						{
30458							current = this.selection.getCurrent();
30459							$next = $(this.keydown.current).next();
30460
30461							if ($next.length !== 0 && $next[0].tagName == 'BR')
30462							{
30463								return this.keydown.insertBreakLine(e);
30464							}
30465							else if (current !== false && $(current).hasClass('redactor-invisible-space'))
30466							{
30467								this.caret.setAfter(current);
30468								$(current).contents().unwrap();
30469
30470								return this.keydown.insertDblBreakLine(e);
30471							}
30472							else
30473							{
30474								if (this.utils.isEndOfEditor())
30475								{
30476									return this.keydown.insertDblBreakLine(e);
30477								}
30478								else if ($next.length === 0 && current === false && typeof $next.context != 'undefined')
30479								{
30480									return this.keydown.insertBreakLine(e);
30481								}
30482
30483								return this.keydown.insertBreakLine(e);
30484							}
30485
30486						}
30487						else if (this.opts.linebreaks && this.keydown.block)
30488						{
30489							setTimeout($.proxy(this.keydown.replaceDivToBreakLine, this), 1);
30490						}
30491						// paragraphs
30492						else if (!this.opts.linebreaks && this.keydown.block)
30493						{
30494							setTimeout($.proxy(this.keydown.replaceDivToParagraph, this), 1);
30495
30496							if (this.keydown.block.tagName === 'LI')
30497							{
30498								current = this.selection.getCurrent();
30499								var $parent = $(current).closest('li', this.$editor[0]);
30500								var $list = $parent.closest('ul,ol', this.$editor[0]);
30501
30502								if ($parent.length !== 0 && this.utils.isEmpty($parent.html()) && $list.next().length === 0 && this.utils.isEmpty($list.find("li").last().html()))
30503								{
30504									$list.find("li").last().remove();
30505
30506									var node = $(this.opts.emptyHtml);
30507									$list.after(node);
30508									this.caret.setStart(node);
30509
30510									return false;
30511								}
30512							}
30513						}
30514						else if (!this.opts.linebreaks && !this.keydown.block)
30515						{
30516							return this.keydown.insertParagraph(e);
30517						}
30518					}
30519
30520					// Shift+Enter or Ctrl+Enter
30521					if (key === this.keyCode.ENTER && (e.ctrlKey || e.shiftKey))
30522					{
30523						return this.keydown.onShiftEnter(e);
30524					}
30525
30526
30527					// tab or cmd + [
30528					if (key === this.keyCode.TAB || e.metaKey && key === 221 || e.metaKey && key === 219)
30529					{
30530						return this.keydown.onTab(e, key);
30531					}
30532
30533					// image delete and backspace
30534					if (key === this.keyCode.BACKSPACE || key === this.keyCode.DELETE)
30535					{
30536						var nodes = this.selection.getNodes();
30537
30538						if (nodes)
30539						{
30540							var len = nodes.length;
30541							var last;
30542							for (var i = 0; i < len; i++)
30543							{
30544								var children = $(nodes[i]).children('img');
30545								if (children.length !== 0)
30546								{
30547									var self = this;
30548									$.each(children, function(z,s)
30549									{
30550										var $s = $(s);
30551										if ($s.css('float') != 'none') return;
30552
30553										// image delete callback
30554										self.core.setCallback('imageDelete', s.src, $s);
30555										last = s;
30556									});
30557								}
30558								else if (nodes[i].tagName == 'IMG')
30559								{
30560									if (last != nodes[i])
30561									{
30562										// image delete callback
30563										this.core.setCallback('imageDelete', nodes[i].src, $(nodes[i]));
30564										last = nodes[i];
30565									}
30566								}
30567							}
30568						}
30569					}
30570
30571					// backspace
30572					if (key === this.keyCode.BACKSPACE)
30573					{
30574						// backspace as outdent
30575						var block = this.selection.getBlock();
30576						var indented = ($(block).css('margin-left') !== '0px');
30577						if (block && indented && this.range.collapsed && this.utils.isStartOfElement())
30578						{
30579							this.indent.decrease();
30580							e.preventDefault();
30581							return;
30582						}
30583
30584						// remove hr in FF
30585						if (this.utils.browser('mozilla'))
30586						{
30587							var prev = this.selection.getPrev();
30588							var prev2 = $(prev).prev()[0];
30589							if (prev && prev.tagName === 'HR') $(prev).remove();
30590							if (prev2 && prev2.tagName === 'HR') $(prev2).remove();
30591						}
30592
30593						this.keydown.removeInvisibleSpace();
30594						this.keydown.removeEmptyListInTable(e);
30595					}
30596
30597					this.code.sync();
30598				},
30599				checkEvents: function(arrow, key)
30600				{
30601					if (!arrow && (this.core.getEvent() == 'click' || this.core.getEvent() == 'arrow'))
30602					{
30603						this.core.addEvent(false);
30604
30605						if (this.keydown.checkKeyEvents(key))
30606						{
30607							this.buffer.set();
30608						}
30609					}
30610				},
30611				checkKeyEvents: function(key)
30612				{
30613					var k = this.keyCode;
30614					var keys = [k.BACKSPACE, k.DELETE, k.ENTER, k.ESC, k.TAB, k.CTRL, k.META, k.ALT, k.SHIFT];
30615
30616					return ($.inArray(key, keys) == -1) ? true : false;
30617
30618				},
30619				addArrowsEvent: function(arrow)
30620				{
30621					if (!arrow) return;
30622
30623					if ((this.core.getEvent() == 'click' || this.core.getEvent() == 'arrow'))
30624					{
30625						this.core.addEvent(false);
30626						return;
30627					}
30628
30629				    this.core.addEvent('arrow');
30630				},
30631				setupBuffer: function(e, key)
30632				{
30633					if (this.keydown.ctrl && key === 90 && !e.shiftKey && !e.altKey && this.opts.buffer.length) // z key
30634					{
30635						e.preventDefault();
30636						this.buffer.undo();
30637						return;
30638					}
30639					// undo
30640					else if (this.keydown.ctrl && key === 90 && e.shiftKey && !e.altKey && this.opts.rebuffer.length !== 0)
30641					{
30642						e.preventDefault();
30643						this.buffer.redo();
30644						return;
30645					}
30646					else if (!this.keydown.ctrl)
30647					{
30648						if (key == this.keyCode.BACKSPACE || key == this.keyCode.DELETE || (key == this.keyCode.ENTER && !e.ctrlKey && !e.shiftKey))
30649						{
30650							this.buffer.set();
30651						}
30652					}
30653				},
30654				setupSelectAll: function(e, key)
30655				{
30656					if (this.keydown.ctrl && key === 65)
30657					{
30658						this.utils.enableSelectAll();
30659					}
30660					else if (key != this.keyCode.LEFT_WIN && !this.keydown.ctrl)
30661					{
30662						this.utils.disableSelectAll();
30663					}
30664				},
30665				onArrowDown: function()
30666				{
30667					var tags = [this.keydown.blockquote, this.keydown.pre, this.keydown.figcaption];
30668
30669					for (var i = 0; i < tags.length; i++)
30670					{
30671						if (tags[i])
30672						{
30673							this.keydown.insertAfterLastElement(tags[i]);
30674							return false;
30675						}
30676					}
30677				},
30678				onShiftEnter: function(e)
30679				{
30680					this.buffer.set();
30681
30682					if (this.utils.isEndOfElement())
30683					{
30684						return this.keydown.insertDblBreakLine(e);
30685					}
30686
30687					return this.keydown.insertBreakLine(e);
30688				},
30689				onTab: function(e, key)
30690				{
30691					if (!this.opts.tabKey) return true;
30692					if (this.utils.isEmpty(this.code.get()) && this.opts.tabAsSpaces === false) return true;
30693
30694					e.preventDefault();
30695
30696					var node;
30697					if (this.keydown.pre && !e.shiftKey)
30698					{
30699						node = (this.opts.preSpaces) ? document.createTextNode(Array(this.opts.preSpaces + 1).join('\u00a0')) : document.createTextNode('\t');
30700						this.insert.node(node);
30701						this.code.sync();
30702					}
30703					else if (this.opts.tabAsSpaces !== false)
30704					{
30705						node = document.createTextNode(Array(this.opts.tabAsSpaces + 1).join('\u00a0'));
30706						this.insert.node(node);
30707						this.code.sync();
30708					}
30709					else
30710					{
30711						if (e.metaKey && key === 219) this.indent.decrease();
30712						else if (e.metaKey && key === 221) this.indent.increase();
30713						else if (!e.shiftKey) this.indent.increase();
30714						else this.indent.decrease();
30715					}
30716
30717					return false;
30718				},
30719				replaceDivToBreakLine: function()
30720				{
30721					var blockElem = this.selection.getBlock();
30722					var blockHtml = blockElem.innerHTML.replace(/<br\s?\/?>/gi, '');
30723					if ((blockElem.tagName === 'DIV' || blockElem.tagName === 'P') && blockHtml === '' && !$(blockElem).hasClass('redactor-editor'))
30724					{
30725						var br = document.createElement('br');
30726
30727						$(blockElem).replaceWith(br);
30728						this.caret.setBefore(br);
30729
30730						this.code.sync();
30731
30732						return false;
30733					}
30734				},
30735				replaceDivToParagraph: function()
30736				{
30737					var blockElem = this.selection.getBlock();
30738					var blockHtml = blockElem.innerHTML.replace(/<br\s?\/?>/gi, '');
30739					if (blockElem.tagName === 'DIV' && this.utils.isEmpty(blockHtml) && !$(blockElem).hasClass('redactor-editor'))
30740					{
30741						var p = document.createElement('p');
30742						p.innerHTML = this.opts.invisibleSpace;
30743
30744						$(blockElem).replaceWith(p);
30745						this.caret.setStart(p);
30746
30747						this.code.sync();
30748
30749						return false;
30750					}
30751					else if (this.opts.cleanStyleOnEnter && blockElem.tagName == 'P')
30752					{
30753						$(blockElem).removeAttr('class').removeAttr('style');
30754					}
30755				},
30756				insertParagraph: function(e)
30757				{
30758					e.preventDefault();
30759
30760					this.selection.get();
30761
30762					var p = document.createElement('p');
30763					p.innerHTML = this.opts.invisibleSpace;
30764
30765					this.range.deleteContents();
30766					this.range.insertNode(p);
30767
30768					this.caret.setStart(p);
30769
30770					this.code.sync();
30771
30772					return false;
30773				},
30774				exitFromBlockquote: function(e)
30775				{
30776					if (!this.utils.isEndOfElement()) return;
30777
30778					var tmp = $.trim($(this.keydown.block).html());
30779					if (tmp.search(/(<br\s?\/?>){2}$/i) != -1)
30780					{
30781						e.preventDefault();
30782
30783						if (this.opts.linebreaks)
30784						{
30785							var br = document.createElement('br');
30786							$(this.keydown.blockquote).after(br);
30787
30788							this.caret.setBefore(br);
30789							$(this.keydown.block).html(tmp.replace(/<br\s?\/?>$/i, ''));
30790						}
30791						else
30792						{
30793							var node = $(this.opts.emptyHtml);
30794							$(this.keydown.blockquote).after(node);
30795							this.caret.setStart(node);
30796						}
30797
30798						return true;
30799
30800					}
30801
30802					return;
30803
30804				},
30805				insertAfterLastElement: function(element)
30806				{
30807					if (!this.utils.isEndOfElement()) return;
30808
30809					this.buffer.set();
30810
30811					if (this.opts.linebreaks)
30812					{
30813						var contents = $('<div>').append($.trim(this.$editor.html())).contents();
30814						var last = contents.last()[0];
30815						if (last.tagName == 'SPAN' && last.innerHTML === '')
30816						{
30817							last = contents.prev()[0];
30818						}
30819
30820						if (this.utils.getOuterHtml(last) != this.utils.getOuterHtml(element)) return;
30821
30822						var br = document.createElement('br');
30823						$(element).after(br);
30824						this.caret.setAfter(br);
30825
30826					}
30827					else
30828					{
30829						if (this.$editor.contents().last()[0] !== element) return;
30830
30831						var node = $(this.opts.emptyHtml);
30832						$(element).after(node);
30833						this.caret.setStart(node);
30834					}
30835				},
30836				insertNewLine: function(e)
30837				{
30838					e.preventDefault();
30839
30840					var node = document.createTextNode('\n');
30841
30842					this.selection.get();
30843
30844					this.range.deleteContents();
30845					this.range.insertNode(node);
30846
30847					this.caret.setAfter(node);
30848
30849					this.code.sync();
30850
30851					return false;
30852				},
30853				insertBreakLine: function(e)
30854				{
30855					return this.keydown.insertBreakLineProcessing(e);
30856				},
30857				insertDblBreakLine: function(e)
30858				{
30859					return this.keydown.insertBreakLineProcessing(e, true);
30860				},
30861				insertBreakLineProcessing: function(e, dbl)
30862				{
30863					e.stopPropagation();
30864
30865					this.selection.get();
30866
30867					var br1 = document.createElement('br');
30868
30869					if (this.utils.browser('msie'))
30870					{
30871						this.range.collapse(false);
30872						this.range.setEnd(this.range.endContainer, this.range.endOffset);
30873					}
30874					else
30875					{
30876						this.range.deleteContents();
30877					}
30878
30879					this.range.insertNode(br1);
30880
30881					// move br outside A tag
30882					var $parentA = $(br1).parent("a");
30883
30884					if ($parentA.length > 0)
30885					{
30886						$parentA.find(br1).remove();
30887						$parentA.after(br1);
30888					}
30889
30890					if (dbl === true)
30891					{
30892						var $next = $(br1).next();
30893						if ($next.length !== 0 && $next[0].tagName === 'BR' && this.utils.isEndOfEditor())
30894						{
30895							this.caret.setAfter(br1);
30896							this.code.sync();
30897							return false;
30898						}
30899
30900						var br2 = document.createElement('br');
30901
30902						this.range.insertNode(br2);
30903						this.caret.setAfter(br2);
30904					}
30905					else
30906					{
30907						// caret does not move after the br visual
30908						if (this.utils.browser('msie'))
30909						{
30910							var space = document.createElement('span');
30911							space.innerHTML = '&#x200b;';
30912
30913							$(br1).after(space);
30914
30915							this.range.setStartAfter(space);
30916							this.range.setEndAfter(space);
30917							$(space).remove();
30918						}
30919						else
30920						{
30921							var range = document.createRange();
30922							range.setStartAfter(br1);
30923							range.collapse(true);
30924							var selection = window.getSelection();
30925							selection.removeAllRanges();
30926							selection.addRange(range);
30927						}
30928					}
30929
30930					this.code.sync();
30931					return false;
30932				},
30933				removeInvisibleSpace: function()
30934				{
30935					var $current = $(this.keydown.current);
30936					if ($current.text().search(/^\u200B$/g) === 0)
30937					{
30938						$current.remove();
30939					}
30940				},
30941				removeEmptyListInTable: function(e)
30942				{
30943					var $current = $(this.keydown.current);
30944					var $parent = $(this.keydown.parent);
30945					var td = $current.closest('td', this.$editor[0]);
30946
30947					if (td.length !== 0 && $current.closest('li', this.$editor[0]) && $parent.children('li').length === 1)
30948					{
30949						if (!this.utils.isEmpty($current.text())) return;
30950
30951						e.preventDefault();
30952
30953						$current.remove();
30954						$parent.remove();
30955
30956						this.caret.setStart(td);
30957					}
30958				}
30959			};
30960		},
30961		keyup: function()
30962		{
30963			return {
30964				init: function(e)
30965				{
30966
30967					if (this.rtePaste) return;
30968
30969					var key = e.which;
30970
30971					this.keyup.current = this.selection.getCurrent();
30972					this.keyup.parent = this.selection.getParent();
30973					var $parent = this.utils.isRedactorParent($(this.keyup.parent).parent());
30974
30975					// callback
30976					var keyupStop = this.core.setCallback('keyup', e);
30977					if (keyupStop === false)
30978					{
30979						e.preventDefault();
30980						return false;
30981					}
30982
30983					// replace to p before / after the table or body
30984					if (!this.opts.linebreaks && this.keyup.current.nodeType === 3 && this.keyup.current.length <= 1 && (this.keyup.parent === false || this.keyup.parent.tagName == 'BODY'))
30985					{
30986						this.keyup.replaceToParagraph();
30987					}
30988
30989					// replace div after lists
30990					if (!this.opts.linebreaks && this.utils.isRedactorParent(this.keyup.current) && this.keyup.current.tagName === 'DIV')
30991					{
30992						this.keyup.replaceToParagraph(false);
30993					}
30994
30995
30996					if (!this.opts.linebreaks && $(this.keyup.parent).hasClass('redactor-invisible-space') && ($parent === false || $parent[0].tagName == 'BODY'))
30997					{
30998						$(this.keyup.parent).contents().unwrap();
30999						this.keyup.replaceToParagraph();
31000					}
31001
31002					// linkify
31003					if (this.linkify.isEnabled() && this.linkify.isKey(key)) this.linkify.format();
31004
31005					if (key === this.keyCode.DELETE || key === this.keyCode.BACKSPACE)
31006					{
31007						if (this.utils.browser('mozilla'))
31008						{
31009							var td = $(this.keydown.current).closest('td', this.$editor[0]);
31010							if (td.size() !== 0 && td.text() !== '')
31011							{
31012								e.preventDefault();
31013								return false;
31014							}
31015						}
31016
31017						// clear unverified
31018						this.clean.clearUnverified();
31019
31020						if (this.observe.image)
31021						{
31022							e.preventDefault();
31023
31024							this.image.hideResize();
31025
31026							this.buffer.set();
31027							this.image.remove(this.observe.image);
31028							this.observe.image = false;
31029
31030							return false;
31031						}
31032
31033						// remove empty paragraphs
31034						this.$editor.find('p').each($.proxy(function(i, s)
31035						{
31036							this.utils.removeEmpty(i, $(s).html());
31037						}, this));
31038
31039						// remove invisible space
31040						if (this.opts.linebreaks && this.keyup.current && this.keyup.current.tagName == 'DIV' && this.utils.isEmpty(this.keyup.current.innerHTML))
31041						{
31042							$(this.keyup.current).after(this.selection.getMarkerAsHtml());
31043							this.selection.restore();
31044							$(this.keyup.current).remove();
31045						}
31046
31047						this.keyup.removeEmptyLists();
31048
31049						// if empty
31050						return this.keyup.formatEmpty(e);
31051					}
31052				},
31053				replaceToParagraph: function(clone)
31054				{
31055					var $current = $(this.keyup.current);
31056
31057					var node;
31058					if (clone === false)
31059					{
31060						node = $('<p>').append($current.html());
31061					}
31062					else
31063					{
31064						node = $('<p>').append($current.clone());
31065					}
31066
31067					$current.replaceWith(node);
31068					var next = $(node).next();
31069					if (typeof(next[0]) !== 'undefined' && next[0].tagName == 'BR')
31070					{
31071						next.remove();
31072					}
31073
31074					this.caret.setEnd(node);
31075				},
31076				removeEmptyLists: function()
31077				{
31078					var removeIt = function()
31079					{
31080						var html = $.trim(this.innerHTML).replace(/\/t\/n/g, '');
31081						if (html === '')
31082						{
31083							$(this).remove();
31084						}
31085					};
31086
31087					this.$editor.find('li').each(removeIt);
31088					this.$editor.find('ul, ol').each(removeIt);
31089				},
31090				formatEmpty: function(e)
31091				{
31092					var html = $.trim(this.$editor.html());
31093
31094					if (!this.utils.isEmpty(html)) return;
31095
31096					e.preventDefault();
31097
31098					if (this.opts.linebreaks)
31099					{
31100						this.$editor.html(this.selection.getMarkerAsHtml());
31101						this.selection.restore();
31102					}
31103					else
31104					{
31105						this.$editor.html(this.opts.emptyHtml);
31106						this.focus.setStart();
31107					}
31108
31109					this.code.sync();
31110
31111					return false;
31112				}
31113			};
31114		},
31115		lang: function()
31116		{
31117			return {
31118				load: function()
31119				{
31120					this.opts.curLang = this.opts.langs[this.opts.lang];
31121				},
31122				get: function(name)
31123				{
31124					return (typeof this.opts.curLang[name] != 'undefined') ? this.opts.curLang[name] : '';
31125				}
31126			};
31127		},
31128		line: function()
31129		{
31130			return {
31131				insert: function()
31132				{
31133					this.buffer.set();
31134
31135					var blocks = this.selection.getBlocks();
31136 					if (blocks[0] !== false && this.line.isExceptLastOrFirst(blocks))
31137	 				{
31138	 					if (!this.utils.browser('msie')) this.$editor.focus();
31139	 					return;
31140					}
31141
31142					if (this.utils.browser('msie'))
31143					{
31144						this.line.insertInIe();
31145					}
31146					else
31147					{
31148						this.line.insertInOthersBrowsers();
31149					}
31150				},
31151				isExceptLastOrFirst: function(blocks)
31152				{
31153					var exceptTags = ['li', 'td', 'th', 'blockquote', 'figcaption', 'pre', 'dl', 'dt', 'dd'];
31154
31155					var first = blocks[0].tagName.toLowerCase();
31156					var last = this.selection.getLastBlock();
31157
31158					last = (typeof last == 'undefined') ? first : last.tagName.toLowerCase();
31159
31160					var firstFound = $.inArray(first, exceptTags) != -1;
31161					var lastFound = $.inArray(last, exceptTags) != -1;
31162
31163					if ((firstFound && lastFound) || firstFound)
31164					{
31165						return true;
31166					}
31167				},
31168				insertInIe: function()
31169				{
31170					this.utils.saveScroll();
31171					this.buffer.set();
31172
31173					this.insert.node(document.createElement('hr'));
31174
31175					this.utils.restoreScroll();
31176					this.code.sync();
31177				},
31178				insertInOthersBrowsers: function()
31179				{
31180					this.buffer.set();
31181
31182					var extra = '<p id="redactor-insert-line"><br /></p>';
31183					if (this.opts.linebreaks) extra = '<br id="redactor-insert-line">';
31184
31185					document.execCommand('insertHtml', false, '<hr>' + extra);
31186
31187					this.line.setFocus();
31188					this.code.sync();
31189				},
31190				setFocus: function()
31191				{
31192					var node = this.$editor.find('#redactor-insert-line');
31193					var next = $(node).next()[0];
31194					var target = next;
31195					if (this.utils.browser('mozilla') && next && next.innerHTML === '')
31196					{
31197						target = $(next).next()[0];
31198						$(next).remove();
31199					}
31200
31201					if (target)
31202					{
31203						node.remove();
31204
31205						if (!this.opts.linebreaks)
31206						{
31207							this.$editor.focus();
31208							this.line.setStart(target);
31209						}
31210
31211					}
31212					else
31213					{
31214
31215						node.removeAttr('id');
31216						this.line.setStart(node[0]);
31217					}
31218				},
31219				setStart: function(node)
31220				{
31221					if (typeof node === 'undefined') return;
31222
31223					var textNode = document.createTextNode('\u200B');
31224
31225					this.selection.get();
31226					this.range.setStart(node, 0);
31227					this.range.insertNode(textNode);
31228					this.range.collapse(true);
31229					this.selection.addRange();
31230
31231				}
31232			};
31233		},
31234		link: function()
31235		{
31236			return {
31237				show: function(e)
31238				{
31239					if (typeof e != 'undefined' && e.preventDefault) e.preventDefault();
31240
31241					if (!this.observe.isCurrent('a'))
31242					{
31243						this.modal.load('link', this.lang.get('link_insert'), 600);
31244					}
31245					else
31246					{
31247						this.modal.load('link', this.lang.get('link_edit'), 600);
31248					}
31249
31250					this.modal.createCancelButton();
31251
31252					var buttonText = !this.observe.isCurrent('a') ? this.lang.get('insert') : this.lang.get('edit');
31253
31254					this.link.buttonInsert = this.modal.createActionButton(buttonText);
31255
31256					this.selection.get();
31257
31258					this.link.getData();
31259					this.link.cleanUrl();
31260
31261					if (this.link.target == '_blank') $('#redactor-link-blank').prop('checked', true);
31262
31263					this.link.$inputUrl = $('#redactor-link-url');
31264					this.link.$inputText = $('#redactor-link-url-text');
31265
31266					this.link.$inputText.val(this.link.text);
31267					this.link.$inputUrl.val(this.link.url);
31268
31269					this.link.buttonInsert.on('click', $.proxy(this.link.insert, this));
31270
31271					// hide link's tooltip
31272					$('.redactor-link-tooltip').remove();
31273
31274					// show modal
31275					this.selection.save();
31276					this.modal.show();
31277					this.link.$inputUrl.focus();
31278				},
31279				cleanUrl: function()
31280				{
31281					var thref = self.location.href.replace(/\/$/i, '');
31282
31283					if (typeof this.link.url !== "undefined")
31284					{
31285						this.link.url = this.link.url.replace(thref, '');
31286						this.link.url = this.link.url.replace(/^\/#/, '#');
31287						this.link.url = this.link.url.replace('mailto:', '');
31288
31289						// remove host from href
31290						if (!this.opts.linkProtocol)
31291						{
31292							var re = new RegExp('^(http|ftp|https)://' + self.location.host, 'i');
31293							this.link.url = this.link.url.replace(re, '');
31294						}
31295					}
31296				},
31297				getData: function()
31298				{
31299					this.link.$node = false;
31300
31301					var $el = $(this.selection.getCurrent()).closest('a', this.$editor[0]);
31302					if ($el.length !== 0 && $el[0].tagName === 'A')
31303					{
31304						this.link.$node = $el;
31305
31306						this.link.url = $el.attr('href');
31307						this.link.text = $el.text();
31308						this.link.target = $el.attr('target');
31309					}
31310					else
31311					{
31312						this.link.text = this.sel.toString();
31313						this.link.url = '';
31314						this.link.target = '';
31315					}
31316
31317				},
31318				insert: function()
31319				{
31320					this.placeholder.remove();
31321
31322					var target = '';
31323					var link = this.link.$inputUrl.val();
31324					var text = this.link.$inputText.val().replace(/(<([^>]+)>)/ig,"");
31325
31326					if ($.trim(link) === '')
31327					{
31328						this.link.$inputUrl.addClass('redactor-input-error').on('keyup', function()
31329						{
31330							$(this).removeClass('redactor-input-error');
31331							$(this).off('keyup');
31332
31333						});
31334
31335						return;
31336					}
31337
31338					// mailto
31339					if (link.search('@') != -1 && /(http|ftp|https):\/\//i.test(link) === false)
31340					{
31341						link = link.replace('mailto:', '');
31342						link = 'mailto:' + link;
31343					}
31344					// url, not anchor
31345					else if (link.search('#') !== 0)
31346					{
31347						if ($('#redactor-link-blank').prop('checked'))
31348						{
31349							target = '_blank';
31350						}
31351
31352						// test url (add protocol)
31353						var pattern = '((xn--)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,}';
31354						var re = new RegExp('^(http|ftp|https)://' + pattern, 'i');
31355						var re2 = new RegExp('^' + pattern, 'i');
31356						var re3 = new RegExp('\.(html|php)$', 'i');
31357						if (link.search(re) == -1 && link.search(re3) == -1 && link.search(re2) === 0 && this.opts.linkProtocol)
31358						{
31359							link = this.opts.linkProtocol + '://' + link;
31360						}
31361					}
31362
31363					this.link.set(text, link, target);
31364					this.modal.close();
31365				},
31366				set: function(text, link, target)
31367				{
31368					text = $.trim(text.replace(/<|>/g, ''));
31369
31370					this.selection.restore();
31371					var blocks = this.selection.getBlocks();
31372
31373					if (text === '' && link === '') return;
31374					if (text === '' && link !== '') text = link;
31375
31376					if (this.link.$node)
31377					{
31378						this.buffer.set();
31379
31380						var $link = this.link.$node,
31381							$el   = $link.children();
31382
31383						if ($el.length > 0)
31384						{
31385							while ($el.length)
31386							{
31387								$el = $el.children();
31388							}
31389
31390							$el = $el.end();
31391						}
31392						else
31393						{
31394							$el = $link;
31395						}
31396
31397						$link.attr('href', link);
31398						$el.text(text);
31399
31400						if (target !== '')
31401						{
31402							$link.attr('target', target);
31403						}
31404						else
31405						{
31406							$link.removeAttr('target');
31407						}
31408
31409						this.selection.selectElement($link);
31410
31411						this.code.sync();
31412					}
31413					else
31414					{
31415						if (this.utils.browser('mozilla') && this.link.text === '')
31416						{
31417							var $a = $('<a />').attr('href', link).text(text);
31418							if (target !== '') $a.attr('target', target);
31419
31420							$a = $(this.insert.node($a));
31421
31422							if (this.opts.linebreaks)
31423							{
31424								$a.after('&nbsp;');
31425							}
31426
31427							this.selection.selectElement($a);
31428						}
31429						else
31430						{
31431							var $a;
31432							if (this.utils.browser('msie'))
31433							{
31434								$a = $('<a href="' + link + '">').text(text);
31435								if (target !== '') $a.attr('target', target);
31436
31437								$a = $(this.insert.node($a));
31438
31439								if (this.selection.getText().match(/\s$/))
31440								{
31441									$a.after(" ");
31442								}
31443
31444								this.selection.selectElement($a);
31445							}
31446							else
31447							{
31448								document.execCommand('createLink', false, link);
31449
31450								$a = $(this.selection.getCurrent()).closest('a', this.$editor[0]);
31451								if (this.utils.browser('mozilla'))
31452								{
31453									$a = $('a[_moz_dirty=""]');
31454								}
31455
31456								if (target !== '') $a.attr('target', target);
31457								$a.removeAttr('style').removeAttr('_moz_dirty');
31458
31459								if (this.selection.getText().match(/\s$/))
31460								{
31461									$a.after(" ");
31462								}
31463
31464								if (this.link.text !== '' || this.link.text != text)
31465								{
31466									if (!this.opts.linebreaks && blocks && blocks.length <= 1)
31467									{
31468										$a.text(text);
31469									}
31470									else if (this.opts.linebreaks)
31471									{
31472										$a.text(text);
31473									}
31474
31475									this.selection.selectElement($a);
31476								}
31477							}
31478						}
31479
31480						this.code.sync();
31481						this.core.setCallback('insertedLink', $a);
31482
31483					}
31484
31485					// link tooltip
31486					setTimeout($.proxy(function()
31487					{
31488						this.observe.links();
31489
31490					}, this), 5);
31491				},
31492				unlink: function(e)
31493				{
31494					if (typeof e != 'undefined' && e.preventDefault)
31495					{
31496						e.preventDefault();
31497					}
31498
31499					var nodes = this.selection.getNodes();
31500					if (!nodes) return;
31501
31502					this.buffer.set();
31503
31504					var len = nodes.length;
31505					var links = [];
31506					for (var i = 0; i < len; i++)
31507					{
31508						if (nodes[i].tagName === 'A')
31509						{
31510							links.push(nodes[i]);
31511						}
31512
31513						var $node = $(nodes[i]).closest('a', this.$editor[0]);
31514						$node.replaceWith($node.contents());
31515					}
31516
31517					this.core.setCallback('deletedLink', links);
31518
31519					// hide link's tooltip
31520					$('.redactor-link-tooltip').remove();
31521
31522					this.code.sync();
31523
31524				},
31525				toggleClass: function(className)
31526				{
31527					this.link.setClass(className, 'toggleClass');
31528				},
31529				addClass: function(className)
31530				{
31531					this.link.setClass(className, 'addClass');
31532				},
31533				removeClass: function(className)
31534				{
31535					this.link.setClass(className, 'removeClass');
31536				},
31537				setClass: function(className, func)
31538				{
31539					var links = this.selection.getInlinesTags(['a']);
31540					if (links === false) return;
31541
31542					$.each(links, function()
31543					{
31544						$(this)[func](className);
31545					});
31546				}
31547			};
31548		},
31549		linkify: function()
31550		{
31551			return {
31552				isKey: function(key)
31553				{
31554					return key == this.keyCode.ENTER || key == this.keyCode.SPACE;
31555				},
31556				isEnabled: function()
31557				{
31558					return this.opts.convertLinks && (this.opts.convertUrlLinks || this.opts.convertImageLinks || this.opts.convertVideoLinks) && !this.utils.isCurrentOrParent('PRE');
31559				},
31560				format: function()
31561				{
31562					var linkify = this.linkify,
31563						opts    = this.opts;
31564
31565					this.$editor
31566						.find(":not(iframe,img,a,pre)")
31567						.addBack()
31568						.contents()
31569						.filter(function()
31570						{
31571							return this.nodeType === 3 && $.trim(this.nodeValue) != "" && !$(this).parent().is("pre") && (this.nodeValue.match(opts.linkify.regexps.youtube) || this.nodeValue.match(opts.linkify.regexps.vimeo) || this.nodeValue.match(opts.linkify.regexps.image) || this.nodeValue.match(opts.linkify.regexps.url));
31572						})
31573						.each(function()
31574						{
31575							var text = $(this).text(),
31576								html = text;
31577
31578							if (opts.convertVideoLinks && (html.match(opts.linkify.regexps.youtube) || html.match(opts.linkify.regexps.vimeo)) )
31579							{
31580								html = linkify.convertVideoLinks(html);
31581							}
31582							else if (opts.convertImageLinks && html.match(opts.linkify.regexps.image))
31583							{
31584								html = linkify.convertImages(html);
31585							}
31586							else if (opts.convertUrlLinks)
31587							{
31588								html = linkify.convertLinks(html);
31589							}
31590
31591							$(this).before(text.replace(text, html))
31592								   .remove();
31593						});
31594
31595
31596					var objects = this.$editor.find('.redactor-linkify-object').each(function()
31597					{
31598						var $el = $(this);
31599						$el.removeClass('redactor-linkify-object');
31600						if ($el.attr('class') === '') $el.removeAttr('class');
31601
31602						return $el[0];
31603
31604					});
31605
31606					// callback
31607					setTimeout($.proxy(function()
31608					{
31609						this.observe.load();
31610						this.core.setCallback('linkify', objects);
31611					}, this), 100);
31612
31613					// sync
31614					this.code.sync();
31615				},
31616				convertVideoLinks: function(html)
31617				{
31618					var iframeStart = '<iframe class="redactor-linkify-object" width="500" height="281" src="',
31619						iframeEnd = '" frameborder="0" allowfullscreen></iframe>';
31620
31621					if (html.match(this.opts.linkify.regexps.youtube))
31622					{
31623						html = html.replace(this.opts.linkify.regexps.youtube, iframeStart + '//www.youtube.com/embed/$1' + iframeEnd);
31624					}
31625
31626					if (html.match(this.opts.linkify.regexps.vimeo))
31627					{
31628						html = html.replace(this.opts.linkify.regexps.vimeo, iframeStart + '//player.vimeo.com/video/$2' + iframeEnd);
31629					}
31630
31631					return html;
31632				},
31633				convertImages: function(html)
31634				{
31635					var matches = html.match(this.opts.linkify.regexps.image);
31636
31637					if (matches)
31638					{
31639						html = html.replace(html, '<img src="' + matches + '" class="redactor-linkify-object" />');
31640
31641						if (this.opts.linebreaks)
31642						{
31643							if (!this.utils.isEmpty(this.code.get()))
31644							{
31645								html = '<br>' + html;
31646							}
31647						}
31648
31649						html += '<br>';
31650					}
31651
31652					return html;
31653				},
31654				convertLinks: function(html)
31655				{
31656					var matches = html.match(this.opts.linkify.regexps.url);
31657
31658					if (matches)
31659					{
31660						matches = $.grep(matches, function(v, k) { return $.inArray(v, matches) === k; });
31661
31662						var length = matches.length;
31663
31664						for (var i = 0; i < length; i++)
31665						{
31666							var href = matches[i],
31667								text = href,
31668								linkProtocol = this.opts.linkProtocol + '://';
31669
31670							if (href.match(/(https?|ftp):\/\//i) !== null)
31671							{
31672								linkProtocol = "";
31673							}
31674
31675							if (text.length > this.opts.linkSize)
31676							{
31677								text = text.substring(0, this.opts.linkSize) + '...';
31678							}
31679
31680							if (text.search('%') === -1)
31681							{
31682								text = decodeURIComponent(text);
31683							}
31684
31685							var regexB = "\\b";
31686
31687							if ($.inArray(href.slice(-1), ["/", "&", "="]) != -1)
31688							{
31689								regexB = "";
31690							}
31691
31692							// escaping url
31693							var regexp = new RegExp('(' + href.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + regexB + ')', 'g');
31694
31695							html = html.replace(regexp, '<a href="' + linkProtocol + $.trim(href) + '" class="redactor-linkify-object">' + $.trim(text) + '</a>');
31696						}
31697					}
31698
31699					return html;
31700				}
31701			};
31702		},
31703		list: function()
31704		{
31705			return {
31706				toggle: function(cmd)
31707				{
31708					this.placeholder.remove();
31709
31710					if (!this.utils.browser('msie') && !this.opts.linebreaks)
31711					{
31712						this.$editor.focus();
31713					}
31714
31715					this.buffer.set();
31716					this.selection.save();
31717
31718					var parent = this.selection.getParent();
31719					var $list = $(parent).closest('ol, ul', this.$editor[0]);
31720
31721					if (!this.utils.isRedactorParent($list) && $list.length !== 0)
31722					{
31723						$list = false;
31724					}
31725
31726					var isUnorderedCmdOrdered, isOrderedCmdUnordered;
31727					var remove = false;
31728					if ($list && $list.length)
31729					{
31730						remove = true;
31731						var listTag = $list[0].tagName;
31732
31733						isUnorderedCmdOrdered = (cmd === 'orderedlist' && listTag === 'UL');
31734						isOrderedCmdUnordered = (cmd === 'unorderedlist' && listTag === 'OL');
31735					}
31736
31737					if (isUnorderedCmdOrdered)
31738					{
31739						this.utils.replaceToTag($list, 'ol');
31740					}
31741					else if (isOrderedCmdUnordered)
31742					{
31743						this.utils.replaceToTag($list, 'ul');
31744					}
31745					else
31746					{
31747						if (remove)
31748						{
31749							this.list.remove(cmd, $list);
31750						}
31751						else
31752						{
31753							this.list.insert(cmd);
31754						}
31755					}
31756
31757					this.selection.restore();
31758					this.code.sync();
31759
31760				},
31761				insert: function(cmd)
31762				{
31763					var current = this.selection.getCurrent();
31764					var $td = $(current).closest('td, th', this.$editor[0]);
31765
31766					if (this.utils.browser('msie') && this.opts.linebreaks)
31767					{
31768						this.list.insertInIe(cmd);
31769					}
31770					else
31771					{
31772						document.execCommand('insert' + cmd);
31773					}
31774
31775					var parent = this.selection.getParent();
31776					var $list = $(parent).closest('ol, ul', this.$editor[0]);
31777					if ($td.length !== 0)
31778					{
31779						var newTd = $td.clone();
31780						$td.after(newTd).remove('');
31781					}
31782
31783
31784					if (this.utils.isEmpty($list.find('li').text()))
31785					{
31786						var $children = $list.children('li');
31787						$children.find('br').remove();
31788						$children.append(this.selection.getMarkerAsHtml());
31789
31790						if (this.opts.linebreaks && this.utils.browser('mozilla') && $children.size() == 2 && this.utils.isEmpty($children.eq(1).text()))
31791						{
31792							$children.eq(1).remove();
31793						}
31794					}
31795
31796					if ($list.length)
31797					{
31798						// remove block-element list wrapper
31799						var $listParent = $list.parent();
31800						if (this.utils.isRedactorParent($listParent) && $listParent[0].tagName != 'LI' && this.utils.isBlock($listParent[0]))
31801						{
31802							$listParent.replaceWith($listParent.contents());
31803						}
31804					}
31805
31806					if (!this.utils.browser('msie'))
31807					{
31808						this.$editor.focus();
31809					}
31810
31811
31812					this.clean.clearUnverified();
31813				},
31814				insertInIe: function(cmd)
31815				{
31816					var wrapper = this.selection.wrap('div');
31817					var wrapperHtml = $(wrapper).html();
31818
31819					var tmpList = (cmd == 'orderedlist') ? $('<ol>') : $('<ul>');
31820					var tmpLi = $('<li>');
31821
31822					if ($.trim(wrapperHtml) === '')
31823					{
31824						tmpLi.append(this.selection.getMarkerAsHtml());
31825						tmpList.append(tmpLi);
31826						this.$editor.find('#selection-marker-1').replaceWith(tmpList);
31827					}
31828					else
31829					{
31830						var items = wrapperHtml.split(/<br\s?\/?>/gi);
31831						if (items)
31832						{
31833							for (var i = 0; i < items.length; i++)
31834							{
31835								if ($.trim(items[i]) !== '')
31836								{
31837									tmpList.append($('<li>').html(items[i]));
31838								}
31839							}
31840						}
31841						else
31842						{
31843							tmpLi.append(wrapperHtml);
31844							tmpList.append(tmpLi);
31845						}
31846
31847						$(wrapper).replaceWith(tmpList);
31848					}
31849				},
31850				remove: function(cmd, $list)
31851				{
31852					if ($.inArray('ul', this.selection.getBlocks())) cmd = 'unorderedlist';
31853
31854					document.execCommand('insert' + cmd);
31855
31856					var $current = $(this.selection.getCurrent());
31857					this.indent.fixEmptyIndent();
31858
31859					if (!this.opts.linebreaks && $current.closest('li, th, td', this.$editor[0]).length === 0)
31860					{
31861						document.execCommand('formatblock', false, 'p');
31862						this.$editor.find('ul, ol, blockquote').each($.proxy(this.utils.removeEmpty, this));
31863					}
31864
31865					var $table = $(this.selection.getCurrent()).closest('table', this.$editor[0]);
31866					var $prev = $table.prev();
31867					if (!this.opts.linebreaks && $table.length !== 0 && $prev.length !== 0 && $prev[0].tagName == 'BR')
31868					{
31869						$prev.remove();
31870					}
31871
31872					this.clean.clearUnverified();
31873
31874
31875				}
31876			};
31877		},
31878		modal: function()
31879		{
31880			return {
31881				callbacks: {},
31882				loadTemplates: function()
31883				{
31884					this.opts.modal = {
31885						imageEdit: String()
31886						+ '<section id="redactor-modal-image-edit">'
31887							+ '<label>' + this.lang.get('title') + '</label>'
31888							+ '<input type="text" id="redactor-image-title" />'
31889							+ '<label class="redactor-image-link-option">' + this.lang.get('link') + '</label>'
31890							+ '<input type="text" id="redactor-image-link" class="redactor-image-link-option" aria-label="' + this.lang.get('link') + '" />'
31891							+ '<label class="redactor-image-link-option"><input type="checkbox" id="redactor-image-link-blank" aria-label="' + this.lang.get('link_new_tab') + '"> ' + this.lang.get('link_new_tab') + '</label>'
31892							+ '<label class="redactor-image-position-option">' + this.lang.get('image_position') + '</label>'
31893							+ '<select class="redactor-image-position-option" id="redactor-image-align" aria-label="' + this.lang.get('image_position') + '">'
31894								+ '<option value="none">' + this.lang.get('none') + '</option>'
31895								+ '<option value="left">' + this.lang.get('left') + '</option>'
31896								+ '<option value="center">' + this.lang.get('center') + '</option>'
31897								+ '<option value="right">
31897' + this.lang.get('right') + '</option>'
31898							+ '</select>'
31899						+ '</section>',
31900
31901						image: String()
31902						+ '<section id="redactor-modal-image-insert">'
31903							+ '<div id="redactor-modal-image-droparea"></div>'
31904 						+ '</section>',
31905
31906						file: String()
31907						+ '<section id="redactor-modal-file-insert">'
31908							+ '<div id="redactor-modal-file-upload-box">'
31909								+ '<label>' + this.lang.get('filename') + '</label>'
31910								+ '<input type="text" id="redactor-filename" aria-label="' + this.lang.get('filename') + '" /><br><br>'
31911								+ '<div id="redactor-modal-file-upload"></div>'
31912							+ '</div>'
31913						+ '</section>',
31914
31915						link: String()
31916						+ '<section id="redactor-modal-link-insert">'
31917							+ '<label>URL</label>'
31918							+ '<input type="url" id="redactor-link-url" aria-label="URL" />'
31919							+ '<label>' + this.lang.get('text') + '</label>'
31920							+ '<input type="text" id="redactor-link-url-text" aria-label="' + this.lang.get('text') + '" />'
31921							+ '<label><input type="checkbox" id="redactor-link-blank"> ' + this.lang.get('link_new_tab') + '</label>'
31922						+ '</section>'
31923					};
31924
31925
31926					$.extend(this.opts, this.opts.modal);
31927
31928				},
31929				addCallback: function(name, callback)
31930				{
31931					this.modal.callbacks[name] = callback;
31932				},
31933				createTabber: function($modal)
31934				{
31935					this.modal.$tabber = $('<div>').attr('id', 'redactor-modal-tabber');
31936
31937					$modal.prepend(this.modal.$tabber);
31938				},
31939				addTab: function(id, name, active)
31940				{
31941					var $tab = $('<a href="#" rel="tab' + id + '">').text(name);
31942					if (active)
31943					{
31944						$tab.addClass('active');
31945					}
31946
31947					var self = this;
31948					$tab.on('click', function(e)
31949					{
31950						e.preventDefault();
31951						$('.redactor-tab').hide();
31952						$('.redactor-' + $(this).attr('rel')).show();
31953
31954						self.modal.$tabber.find('a').removeClass('active');
31955						$(this).addClass('active');
31956
31957					});
31958
31959					this.modal.$tabber.append($tab);
31960				},
31961				addTemplate: function(name, template)
31962				{
31963					this.opts.modal[name] = template;
31964				},
31965				getTemplate: function(name)
31966				{
31967					return this.opts.modal[name];
31968				},
31969				getModal: function()
31970				{
31971					return this.$modalBody.find('section');
31972				},
31973				load: function(templateName, title, width)
31974				{
31975					this.modal.templateName = templateName;
31976					this.modal.width = width;
31977
31978					this.modal.build();
31979					this.modal.enableEvents();
31980					this.modal.setTitle(title);
31981					this.modal.setDraggable();
31982					this.modal.setContent();
31983
31984					// callbacks
31985					if (typeof this.modal.callbacks[templateName] != 'undefined')
31986					{
31987						this.modal.callbacks[templateName].call(this);
31988					}
31989
31990				},
31991				show: function()
31992				{
31993					this.utils.disableBodyScroll();
31994
31995					if (this.utils.isMobile())
31996					{
31997						this.modal.showOnMobile();
31998					}
31999					else
32000					{
32001						this.modal.showOnDesktop();
32002					}
32003
32004					if (this.opts.highContrast)
32005					{
32006						this.$modalBox.addClass("redactor-modal-contrast");
32007					}
32008
32009					this.$modalOverlay.show();
32010					this.$modalBox.show();
32011
32012					this.$modal.attr('tabindex', '-1');
32013					this.$modal.focus();
32014
32015					this.modal.setButtonsWidth();
32016
32017					this.utils.saveScroll();
32018
32019					// resize
32020					if (!this.utils.isMobile())
32021					{
32022						setTimeout($.proxy(this.modal.showOnDesktop, this), 0);
32023						$(window).on('resize.redactor-modal', $.proxy(this.modal.resize, this));
32024					}
32025
32026					// modal shown callback
32027					this.core.setCallback('modalOpened', this.modal.templateName, this.$modal);
32028
32029					// fix bootstrap modal focus
32030					$(document).off('focusin.modal');
32031
32032					// enter
32033					this.$modal.find('input[type=text],input[type=url],input[type=email]').on('keydown.redactor-modal', $.proxy(this.modal.setEnter, this));
32034				},
32035				showOnDesktop: function()
32036				{
32037					var height = this.$modal.outerHeight();
32038					var windowHeight = $(window).height();
32039					var windowWidth = $(window).width();
32040
32041					if (this.modal.width > windowWidth)
32042					{
32043						this.$modal.css({
32044							width: '96%',
32045							marginTop: (windowHeight/2 - height/2) + 'px'
32046						});
32047						return;
32048					}
32049
32050					if (height > windowHeight)
32051					{
32052						this.$modal.css({
32053							width: this.modal.width + 'px',
32054							marginTop: '20px'
32055						});
32056					}
32057					else
32058					{
32059						this.$modal.css({
32060							width: this.modal.width + 'px',
32061							marginTop: (windowHeight/2 - height/2) + 'px'
32062						});
32063					}
32064				},
32065				showOnMobile: function()
32066				{
32067					this.$modal.css({
32068						width: '96%',
32069						marginTop: '2%'
32070					});
32071
32072				},
32073				resize: function()
32074				{
32075					if (this.utils.isMobile())
32076					{
32077						this.modal.showOnMobile();
32078					}
32079					else
32080					{
32081						this.modal.showOnDesktop();
32082					}
32083				},
32084				setTitle: function(title)
32085				{
32086					this.$modalHeader.html(title);
32087				},
32088				setContent: function()
32089				{
32090					this.$modalBody.html(this.modal.getTemplate(this.modal.templateName));
32091				},
32092				setDraggable: function()
32093				{
32094					if (typeof $.fn.draggable === 'undefined') return;
32095
32096					this.$modal.draggable({ handle: this.$modalHeader });
32097					this.$modalHeader.css('cursor', 'move');
32098				},
32099				setEnter: function(e)
32100				{
32101					if (e.which != 13) return;
32102
32103					e.preventDefault();
32104					this.$modal.find('button.redactor-modal-action-btn').click();
32105				},
32106				createCancelButton: function()
32107				{
32108					var button = $('<button>').addClass('redactor-modal-btn redactor-modal-close-btn').html(this.lang.get('cancel'));
32109					button.on('click', $.proxy(this.modal.close, this));
32110
32111					this.$modalFooter.append(button);
32112				},
32113				createDeleteButton: function(label)
32114				{
32115					return this.modal.createButton(label, 'delete');
32116				},
32117				createActionButton: function(label)
32118				{
32119					return this.modal.createButton(label, 'action');
32120				},
32121				createButton: function(label, className)
32122				{
32123					var button = $('<button>').addClass('redactor-modal-btn').addClass('redactor-modal-' + className + '-btn').html(label);
32124					this.$modalFooter.append(button);
32125
32126					return button;
32127				},
32128				setButtonsWidth: function()
32129				{
32130					var buttons = this.$modalFooter.find('button');
32131					var buttonsSize = buttons.length;
32132					if (buttonsSize === 0) return;
32133
32134					buttons.css('width', (100/buttonsSize) + '%');
32135				},
32136				build: function()
32137				{
32138					this.modal.buildOverlay();
32139
32140					this.$modalBox = $('<div id="redactor-modal-box"/>').hide();
32141					this.$modal = $('<div id="redactor-modal" role="dialog" aria-labelledby="redactor-modal-header" />');
32142					this.$modalHeader = $('<header id="redactor-modal-header"/>');
32143					this.$modalClose = $('<button type="button" id="redactor-modal-close" tabindex="1" aria-label="Close" />').html('&times;');
32144					this.$modalBody = $('<div id="redactor-modal-body" />');
32145					this.$modalFooter = $('<footer />');
32146
32147					this.$modal.append(this.$modalHeader);
32148					this.$modal.append(this.$modalClose);
32149					this.$modal.append(this.$modalBody);
32150					this.$modal.append(this.$modalFooter);
32151					this.$modalBox.append(this.$modal);
32152					this.$modalBox.appendTo(document.body);
32153				},
32154				buildOverlay: function()
32155				{
32156					this.$modalOverlay = $('<div id="redactor-modal-overlay">').hide();
32157					$('body').prepend(this.$modalOverlay);
32158				},
32159				enableEvents: function()
32160				{
32161					this.$modalClose.on('click.redactor-modal', $.proxy(this.modal.close, this));
32162					$(document).on('keyup.redactor-modal', $.proxy(this.modal.closeHandler, this));
32163					this.$editor.on('keyup.redactor-modal', $.proxy(this.modal.closeHandler, this));
32164					this.$modalBox.on('click.redactor-modal', $.proxy(this.modal.close, this));
32165				},
32166				disableEvents: function()
32167				{
32168					this.$modalClose.off('click.redactor-modal');
32169					$(document).off('keyup.redactor-modal');
32170					this.$editor.off('keyup.redactor-modal');
32171					this.$modalBox.off('click.redactor-modal');
32172					$(window).off('resize.redactor-modal');
32173				},
32174				closeHandler: function(e)
32175				{
32176					if (e.which != this.keyCode.ESC) return;
32177
32178					this.modal.close(false);
32179				},
32180				close: function(e)
32181				{
32182					if (e)
32183					{
32184						if (!$(e.target).hasClass('redactor-modal-close-btn') && e.target != this.$modalClose[0] && e.target != this.$modalBox[0])
32185						{
32186							return;
32187						}
32188
32189						e.preventDefault();
32190					}
32191
32192					if (!this.$modalBox) return;
32193
32194					this.modal.disableEvents();
32195					this.utils.enableBodyScroll();
32196
32197					this.$modalOverlay.remove();
32198
32199					this.$modalBox.fadeOut('fast', $.proxy(function()
32200					{
32201						this.$modalBox.remove();
32202
32203						setTimeout($.proxy(this.utils.restoreScroll, this), 0);
32204
32205						if (e !== undefined) this.selection.restore();
32206
32207						$(document.body).css('overflow', this.modal.bodyOveflow);
32208						this.core.setCallback('modalClosed', this.modal.templateName);
32209
32210					}, this));
32211
32212				}
32213			};
32214		},
32215		observe: function()
32216		{
32217			return {
32218				load: function()
32219				{
32220					if (typeof this.opts.destroyed != "undefined") return;
32221
32222					if (this.utils.browser('msie'))
32223					{
32224						var self = this;
32225						this.$editor.find('pre, code').on('mouseover',function()
32226						{
32227							self.$editor.attr('contenteditable', false);
32228							$(this).attr('contenteditable', true);
32229
32230						}).on('mouseout',function()
32231						{
32232							self.$editor.attr('contenteditable', true);
32233							$(this).removeAttr('contenteditable');
32234
32235						});
32236					}
32237
32238					this.observe.images();
32239					this.observe.links();
32240				},
32241				toolbar: function(e, btnName)
32242				{
32243					this.observe.buttons(e, btnName);
32244					this.observe.dropdowns();
32245				},
32246				isCurrent: function($el, $current)
32247				{
32248					if (typeof $current == 'undefined')
32249					{
32250						var $current = $(this.selection.getCurrent());
32251					}
32252
32253					return $current.is($el) || $current.parents($el).length > 0;
32254				},
32255				dropdowns: function()
32256				{
32257					var $current = $(this.selection.getCurrent());
32258
32259					$.each(this.opts.observe.dropdowns, $.proxy(function(key, value)
32260					{
32261						var observe = value.observe,
32262							element = observe.element,
32263							$item   = value.item,
32264							inValues = typeof observe['in'] != 'undefined' ? observe['in'] : false,
32265							outValues = typeof observe['out'] != 'undefined' ? observe['out'] : false;
32266
32267						if ($current.closest(element).size() > 0)
32268						{
32269							this.observe.setDropdownProperties($item, inValues, outValues);
32270						}
32271						else
32272						{
32273							this.observe.setDropdownProperties($item, outValues, inValues);
32274						}
32275					}, this));
32276				},
32277				setDropdownProperties: function($item, addProperties, deleteProperties)
32278				{
32279					if (deleteProperties && typeof deleteProperties['attr'] != 'undefined')
32280					{
32281						this.observe.setDropdownAttr($item, deleteProperties.attr, true);
32282					}
32283
32284					if (typeof addProperties['attr'] != 'undefined')
32285					{
32286						this.observe.setDropdownAttr($item, addProperties.attr);
32287					}
32288
32289					if (typeof addProperties['title'] != 'undefined')
32290					{
32291						$item.text(addProperties['title']);
32292					}
32293				},
32294				setDropdownAttr: function($item, properties, isDelete)
32295				{
32296					$.each(properties, function(key, value)
32297					{
32298						if (key == 'class')
32299						{
32300							if (!isDelete)
32301							{
32302								$item.addClass(value);
32303							}
32304							else
32305							{
32306								$item.removeClass(value);
32307							}
32308						}
32309						else
32310						{
32311							if (!isDelete)
32312							{
32313								$item.attr(key, value);
32314							}
32315							else
32316							{
32317								$item.removeAttr(key);
32318							}
32319						}
32320					});
32321				},
32322				addDropdown: function($item, btnName, btnObject)
32323				{
32324					if (typeof btnObject.observe == "undefined") return;
32325
32326					btnObject.item = $item;
32327
32328					this.opts.observe.dropdowns.push(btnObject);
32329				},
32330				buttons: function(e, btnName)
32331				{
32332					var current = this.selection.getCurrent();
32333					var parent = this.selection.getParent();
32334
32335					if (e !== false)
32336					{
32337						this.button.setInactiveAll();
32338					}
32339					else
32340					{
32341						this.button.setInactiveAll(btnName);
32342					}
32343
32344					if (e === false && btnName !== 'html')
32345					{
32346						if ($.inArray(btnName, this.opts.activeButtons) != -1) this.button.toggleActive(btnName);
32347						return;
32348					}
32349
32350					//var linkButtonName = (this.utils.isCurrentOrParent('A')) ? this.lang.get('link_edit') : this.lang.get('link_insert');
32351					//$('body').find('a.redactor-dropdown-link').text(linkButtonName);
32352
32353					$.each(this.opts.activeButtonsStates, $.proxy(function(key, value)
32354					{
32355						var parentEl = $(parent).closest(key, this.$editor[0]);
32356						var currentEl = $(current).closest(key, this.$editor[0]);
32357
32358						if (parentEl.length !== 0 && !this.utils.isRedactorParent(parentEl)) return;
32359						if (!this.utils.isRedactorParent(currentEl)) return;
32360						if (parentEl.length !== 0 || currentEl.closest(key, this.$editor[0]).length !== 0)
32361						{
32362							this.button.setActive(value);
32363						}
32364
32365					}, this));
32366
32367					var $parent = $(parent).closest(this.opts.alignmentTags.toString().toLowerCase(), this.$editor[0]);
32368					if (this.utils.isRedactorParent(parent) && $parent.length)
32369					{
32370						var align = ($parent.css('text-align') === '') ? 'left' : $parent.css('text-align');
32371						this.button.setActive('align' + align);
32372					}
32373				},
32374				addButton: function(tag, btnName)
32375				{
32376					this.opts.activeButtons.push(btnName);
32377					this.opts.activeButtonsStates[tag] = btnName;
32378				},
32379				images: function()
32380				{
32381					this.$editor.find('img').each($.proxy(function(i, img)
32382					{
32383						var $img = $(img);
32384
32385						// IE fix (when we clicked on an image and then press backspace IE does goes to image's url)
32386						$img.closest('a', this.$editor[0]).on('click', function(e) { e.preventDefault(); });
32387
32388						if (this.utils.browser('msie')) $img.attr('unselectable', 'on');
32389
32390						this.image.setEditable($img);
32391
32392					}, this));
32393
32394					$(document).on('click.redactor-image-delete.' + this.uuid, $.proxy(function(e)
32395					{
32396						this.observe.image = false;
32397						if (e.target.tagName == 'IMG' && this.utils.isRedactorParent(e.target))
32398						{
32399							this.observe.image = (this.observe.image && this.observe.image == e.target) ? false : e.target;
32400						}
32401
32402					}, this));
32403
32404				},
32405				links: function()
32406				{
32407					if (!this.opts.linkTooltip) return;
32408
32409					this.$editor.find('a').on('touchstart.redactor.' + this.uuid + ' click.redactor.' + this.uuid, $.proxy(this.observe.showTooltip, this));
32410					this.$editor.on('touchstart.redactor.' + this.uuid + ' click.redactor.' + this.uuid, $.proxy(this.observe.closeTooltip, this));
32411					$(document).on('touchstart.redactor.' + this.uuid + ' click.redactor.' + this.uuid, $.proxy(this.observe.closeTooltip, this));
32412				},
32413				getTooltipPosition: function($link)
32414				{
32415					return $link.offset();
32416				},
32417				showTooltip: function(e)
32418				{
32419					var $el = $(e.target);
32420
32421					if ($el[0].tagName == 'IMG')
32422						return;
32423
32424					if ($el[0].tagName !== 'A')
32425						$el = $el.closest('a', this.$editor[0]);
32426
32427					if ($el[0].tagName !== 'A')
32428						return;
32429
32430					var $link = $el;
32431
32432					var pos = this.observe.getTooltipPosition($link);
32433					var tooltip = $('<span class="redactor-link-tooltip"></span>');
32434
32435					var href = $link.attr('href');
32436					if (href === undefined)
32437					{
32438						href = '';
32439					}
32440
32441					if (href.length > 24) href = href.substring(0, 24) + '...';
32442
32443					var aLink = $('<a href="' + $link.attr('href') + '" target="_blank" />').html(href).addClass('redactor-link-tooltip-action');
32444					var aEdit = $('<a href="#" />').html(this.lang.get('edit')).on('click', $.proxy(this.link.show, this)).addClass('redactor-link-tooltip-action');
32445					var aUnlink = $('<a href="#" />').html(this.lang.get('unlink')).on('click', $.proxy(this.link.unlink, this)).addClass('redactor-link-tooltip-action');
32446
32447					tooltip.append(aLink).append(' | ').append(aEdit).append(' | ').append(aUnlink);
32448					tooltip.css({
32449						top: (pos.top + parseInt($link.css('line-height'), 10)) + 'px',
32450						left: pos.left + 'px'
32451					});
32452
32453					$('.redactor-link-tooltip').remove();
32454					$('body').append(tooltip);
32455				},
32456				closeTooltip: function(e)
32457				{
32458					e = e.originalEvent || e;
32459
32460					var target = e.target;
32461					var $parent = $(target).closest('a', this.$editor[0]);
32462					if ($parent.length !== 0 && $parent[0].tagName === 'A' && target.tagName !== 'A')
32463					{
32464						return;
32465					}
32466					else if ((target.tagName === 'A' && this.utils.isRedactorParent(target)) || $(target).hasClass('redactor-link-tooltip-action'))
32467					{
32468						return;
32469					}
32470
32471					$('.redactor-link-tooltip').remove();
32472				}
32473
32474			};
32475		},
32476		paragraphize: function()
32477		{
32478			return {
32479				load: function(html)
32480				{
32481					if (this.opts.linebreaks) return html;
32482					if (html === '' || html === '<p></p>') return this.opts.emptyHtml;
32483
32484					html = html + "\n";
32485
32486					this.paragraphize.safes = [];
32487					this.paragraphize.z = 0;
32488
32489					html = html.replace(/(<br\s?\/?>){1,}\n?<\/blockquote>/gi, '</blockquote>');
32490
32491					html = this.paragraphize.getSafes(html);
32492					html = this.paragraphize.getSafesComments(html);
32493					html = this.paragraphize.replaceBreaksToNewLines(html);
32494					html = this.paragraphize.replaceBreaksToParagraphs(html);
32495					html = this.paragraphize.clear(html);
32496					html = this.paragraphize.restoreSafes(html);
32497
32498					html = html.replace(new RegExp('<br\\s?/?>\n?<(' + this.opts.paragraphizeBlocks.join('|') + ')(.*?[^>])>', 'gi'), '<p><br /></p>\n<$1$2>');
32499
32500					return $.trim(html);
32501				},
32502				getSafes: function(html)
32503				{
32504					var $div = $('<div />').append(html);
32505
32506					// remove paragraphs in blockquotes
32507					$div.find('blockquote p').replaceWith(function()
32508					{
32509						return $(this).append('<br />').contents();
32510					});
32511
32512					html = $div.html();
32513
32514					$div.find(this.opts.paragraphizeBlocks.join(', ')).each($.proxy(function(i,s)
32515					{
32516						this.paragraphize.z++;
32517						this.paragraphize.safes[this.paragraphize.z] = s.outerHTML;
32518						html = html.replace(s.outerHTML, '\n{replace' + this.paragraphize.z + '}');
32519
32520					}, this));
32521
32522					return html;
32523				},
32524				getSafesComments: function(html)
32525				{
32526					var commentsMatches = html.match(/<!--([\w\W]*?)-->/gi);
32527
32528					if (!commentsMatches) return html;
32529
32530					$.each(commentsMatches, $.proxy(function(i,s)
32531					{
32532						this.paragraphize.z++;
32533						this.paragraphize.safes[this.paragraphize.z] = s;
32534						html = html.replace(s, '\n{replace' + this.paragraphize.z + '}');
32535					}, this));
32536
32537					return html;
32538				},
32539				restoreSafes: function(html)
32540				{
32541					$.each(this.paragraphize.safes, function(i,s)
32542					{
32543						s = (typeof s !== 'undefined') ? s.replace(/\$/g, '&#36;') : s;
32544						html = html.replace('{replace' + i + '}', s);
32545
32546					});
32547
32548					return html;
32549				},
32550				replaceBreaksToParagraphs: function(html)
32551				{
32552					var htmls = html.split(new RegExp('\n', 'g'), -1);
32553
32554					html = '';
32555					if (htmls)
32556					{
32557						var len = htmls.length;
32558						for (var i = 0; i < len; i++)
32559						{
32560							if (!htmls.hasOwnProperty(i)) return;
32561
32562							if (htmls[i].search('{replace') == -1)
32563							{
32564								htmls[i] = htmls[i].replace(/<p>\n\t?<\/p>/gi, '');
32565								htmls[i] = htmls[i].replace(/<p><\/p>/gi, '');
32566
32567								if (htmls[i] !== '')
32568								{
32569									html += '<p>' +  htmls[i].replace(/^\n+|\n+$/g, "") + "</p>";
32570								}
32571							}
32572							else html += htmls[i];
32573						}
32574					}
32575
32576					return html;
32577				},
32578				replaceBreaksToNewLines: function(html)
32579				{
32580					html = html.replace(/<br \/>\s*<br \/>/gi, "\n\n");
32581					html = html.replace(/<br\s?\/?>\n?<br\s?\/?>/gi, "\n<br /><br />");
32582
32583					html = html.replace(new RegExp("\r\n", 'g'), "\n");
32584					html = html.replace(new RegExp("\r", 'g'), "\n");
32585					html = html.replace(new RegExp("/\n\n+/"), 'g', "\n\n");
32586
32587					return html;
32588				},
32589				clear: function(html)
32590				{
32591					html = html.replace(new RegExp('</blockquote></p>', 'gi'), '</blockquote>');
32592					html = html.replace(new RegExp('<p></blockquote>', 'gi'), '</blockquote>');
32593					html = html.replace(new RegExp('<p><blockquote>', 'gi'), '<blockquote>');
32594					html = html.replace(new RegExp('<blockquote></p>', 'gi'), '<blockquote>');
32595
32596					html = html.replace(new RegExp('<p><p ', 'gi'), '<p ');
32597					html = html.replace(new RegExp('<p><p>
32597', 'gi'), '<p>');
32598					html = html.replace(new RegExp('</p></p>', 'gi'), '</p>');
32599					html = html.replace(new RegExp('<p>\\s?</p>', 'gi'), '');
32600					html = html.replace(new RegExp("\n</p>", 'gi'), '</p>');
32601					html = html.replace(new RegExp('<p>\t?\t?\n?<p>', 'gi'), '<p>');
32602					html = html.replace(new RegExp('<p>\t*</p>', 'gi'), '');
32603
32604					return html;
32605				}
32606			};
32607		},
32608		paste: function()
32609		{
32610			return {
32611				init: function(e)
32612				{
32613					if (!this.opts.cleanOnPaste)
32614					{
32615						setTimeout($.proxy(this.code.sync, this), 1);
32616						return;
32617					}
32618
32619					this.rtePaste = true;
32620
32621					this.buffer.set();
32622					this.selection.save();
32623					this.utils.saveScroll();
32624
32625					this.paste.createPasteBox();
32626
32627					$(window).on('scroll.redactor-freeze', $.proxy(function()
32628					{
32629						$(window).scrollTop(this.saveBodyScroll);
32630
32631					}, this));
32632
32633					setTimeout($.proxy(function()
32634					{
32635						var html = this.$pasteBox.html();
32636
32637						this.$pasteBox.remove();
32638
32639						this.selection.restore();
32640						this.utils.restoreScroll();
32641
32642						this.paste.insert(html);
32643
32644						$(window).off('scroll.redactor-freeze');
32645
32646						if (this.linkify.isEnabled())
32647						{
32648							this.linkify.format();
32649						}
32650
32651					}, this), 1);
32652				},
32653				createPasteBox: function()
32654				{
32655					this.$pasteBox = $('<div>').html('').attr('contenteditable', 'true').css({ position: 'fixed', width: 0, top: 0, left: '-9999px' });
32656
32657					if (this.utils.browser('msie'))
32658					{
32659						this.$box.append(this.$pasteBox);
32660					}
32661					else
32662					{
32663						// bootstrap modal
32664						var $visibleModals = $('.modal-body:visible');
32665						if ($visibleModals.length > 0)
32666						{
32667							$visibleModals.append(this.$pasteBox);
32668						}
32669						else
32670						{
32671							$('body').append(this.$pasteBox);
32672						}
32673					}
32674
32675					this.$pasteBox.get(0).focus();
32676				},
32677				insert: function(html)
32678				{
32679					html = this.core.setCallback('pasteBefore', html);
32680
32681					// clean
32682					html = (this.utils.isSelectAll()) ? this.clean.onPaste(html, false) : this.clean.onPaste(html);
32683
32684					html = this.core.setCallback('paste', html);
32685
32686					if (this.utils.isSelectAll())
32687					{
32688						this.insert.set(html, false);
32689					}
32690					else
32691					{
32692						this.insert.html(html, false);
32693					}
32694
32695					this.utils.disableSelectAll();
32696					this.rtePaste = false;
32697
32698					setTimeout($.proxy(this.clean.clearUnverified, this), 10);
32699
32700					// clean empty spans
32701					setTimeout($.proxy(function()
32702					{
32703						var spans = this.$editor.find('span');
32704						$.each(spans, function(i,s)
32705						{
32706							var html = s.innerHTML.replace(/\u200B/, '');
32707							if (html === '' && s.attributes.length === 0) $(s).remove();
32708
32709						});
32710
32711					}, this), 10);
32712
32713				}
32714			};
32715		},
32716		placeholder: function()
32717		{
32718			return {
32719				enable: function()
32720				{
32721					if (!this.placeholder.is()) return;
32722
32723					this.$editor.attr('placeholder', this.$element.attr('placeholder'));
32724
32725					this.placeholder.toggle();
32726					this.$editor.on('keydown.redactor-placeholder', $.proxy(this.placeholder.toggle, this));
32727				},
32728				toggle: function()
32729				{
32730					setTimeout($.proxy(function()
32731					{
32732						var func = this.utils.isEmpty(this.$editor.html(), false) ? 'addClass' : 'removeClass';
32733						this.$editor[func]('redactor-placeholder');
32734
32735					}, this), 5);
32736				},
32737				remove: function()
32738				{
32739					this.$editor.removeClass('redactor-placeholder');
32740				},
32741				is: function()
32742				{
32743					if (this.opts.placeholder)
32744					{
32745						return this.$element.attr('placeholder', this.opts.placeholder);
32746					}
32747					else
32748					{
32749						return !(typeof this.$element.attr('placeholder') == 'undefined' || this.$element.attr('placeholder') === '');
32750					}
32751				}
32752			};
32753		},
32754		progress: function()
32755		{
32756			return {
32757				show: function()
32758				{
32759					$(document.body).append($('<div id="redactor-progress"><span></span></div>'));
32760					$('#redactor-progress').fadeIn();
32761				},
32762				hide: function()
32763				{
32764					$('#redactor-progress').fadeOut(1500, function()
32765					{
32766						$(this).remove();
32767					});
32768				}
32769
32770			};
32771		},
32772		selection: function()
32773		{
32774			return {
32775				get: function()
32776				{
32777					this.sel = document.getSelection();
32778
32779					if (document.getSelection && this.sel.getRangeAt && this.sel.rangeCount)
32780					{
32781						this.range = this.sel.getRangeAt(0);
32782					}
32783					else
32784					{
32785						this.range = document.createRange();
32786					}
32787				},
32788				addRange: function()
32789				{
32790					try {
32791						this.sel.removeAllRanges();
32792					} catch (e) {}
32793
32794					this.sel.addRange(this.range);
32795				},
32796				getCurrent: function()
32797				{
32798					var el = false;
32799
32800					this.selection.get();
32801
32802					if (this.sel && this.sel.rangeCount > 0)
32803					{
32804						el = this.sel.getRangeAt(0).startContainer;
32805					}
32806
32807					return this.utils.isRedactorParent(el);
32808				},
32809				getParent: function(elem)
32810				{
32811					elem = elem || this.selection.getCurrent();
32812					if (elem)
32813					{
32814						return this.utils.isRedactorParent($(elem).parent()[0]);
32815					}
32816
32817					return false;
32818				},
32819				getPrev: function()
32820				{
32821					return  window.getSelection().anchorNode.previousSibling;
32822				},
32823				getNext: function()
32824				{
32825					return window.getSelection().anchorNode.nextSibling;
32826				},
32827				getBlock: function(node)
32828				{
32829					node = node || this.selection.getCurrent();
32830
32831					while (node)
32832					{
32833						if (this.utils.isBlockTag(node.tagName))
32834						{
32835							return ($(node).hasClass('redactor-editor')) ? false : node;
32836						}
32837
32838						node = node.parentNode;
32839					}
32840
32841					return false;
32842				},
32843				getInlines: function(nodes, tags)
32844				{
32845					this.selection.get();
32846
32847					if (this.range && this.range.collapsed)
32848					{
32849						return false;
32850					}
32851
32852					var inlines = [];
32853					nodes = (typeof nodes == 'undefined' || nodes === false) ? this.selection.getNodes() : nodes;
32854					var inlineTags = this.opts.inlineTags;
32855					inlineTags.push('span');
32856
32857					if (typeof tags !== 'undefined')
32858					{
32859						for (var i = 0; i < tags.length; i++)
32860						{
32861							inlineTags.push(tags[i]);
32862						}
32863					}
32864
32865					$.each(nodes, $.proxy(function(i,node)
32866					{
32867						if ($.inArray(node.tagName.toLowerCase(), inlineTags) != -1)
32868						{
32869							inlines.push(node);
32870						}
32871
32872					}, this));
32873
32874					return (inlines.length === 0) ? false : inlines;
32875				},
32876				getInlinesTags: function(tags)
32877				{
32878					this.selection.get();
32879
32880					if (this.range && this.range.collapsed)
32881					{
32882						return false;
32883					}
32884
32885					var inlines = [];
32886					var nodes =  this.selection.getNodes();
32887					$.each(nodes, $.proxy(function(i,node)
32888					{
32889						if ($.inArray(node.tagName.toLowerCase(), tags) != -1)
32890						{
32891							inlines.push(node);
32892						}
32893
32894					}, this));
32895
32896					return (inlines.length === 0) ? false : inlines;
32897				},
32898				getBlocks: function(nodes)
32899				{
32900					this.selection.get();
32901
32902					if (this.range && this.range.collapsed)
32903					{
32904						return [this.selection.getBlock()];
32905					}
32906
32907					var blocks = [];
32908					nodes = (typeof nodes == 'undefined') ? this.selection.getNodes() : nodes;
32909
32910					$.each(nodes, $.proxy(function(i,node)
32911					{
32912						if (this.utils.isBlock(node))
32913						{
32914							blocks.push(node);
32915						}
32916
32917					}, this));
32918
32919					return (blocks.length === 0) ? [this.selection.getBlock()] : blocks;
32920				},
32921				getLastBlock: function()
32922				{
32923					return this.selection.lastBlock;
32924				},
32925				getNodes: function()
32926				{
32927					this.selection.get();
32928
32929					var startNode = this.selection.getNodesMarker(1);
32930					var endNode = this.selection.getNodesMarker(2);
32931
32932					if (this.range.collapsed === false)
32933					{
32934					   if (window.getSelection) {
32935					        var sel = window.getSelection();
32936					        if (sel.rangeCount > 0) {
32937
32938					            var range = sel.getRangeAt(0);
32939					            var startPointNode = range.startContainer, startOffset = range.startOffset;
32940
32941					            var boundaryRange = range.cloneRange();
32942					            boundaryRange.collapse(false);
32943					            boundaryRange.insertNode(endNode);
32944					            boundaryRange.setStart(startPointNode, startOffset);
32945					            boundaryRange.collapse(true);
32946					            boundaryRange.insertNode(startNode);
32947
32948					            // Reselect the original text
32949					            range.setStartAfter(startNode);
32950					            range.setEndBefore(endNode);
32951					            sel.removeAllRanges();
32952					            sel.addRange(range);
32953					        }
32954					    }
32955					}
32956					else
32957					{
32958						this.selection.setNodesMarker(this.range, startNode, true);
32959						endNode = startNode;
32960					}
32961
32962					var nodes = [];
32963					var counter = 0;
32964
32965					var self = this;
32966					this.$editor.find('*').each(function()
32967					{
32968						if (this == startNode)
32969						{
32970							var parent = $(this).parent();
32971							if (parent.length !== 0 && parent[0].tagName != 'BODY' && self.utils.isRedactorParent(parent[0]))
32972							{
32973								nodes.push(parent[0]);
32974							}
32975
32976							nodes.push(this);
32977							counter = 1;
32978						}
32979						else
32980						{
32981							if (counter > 0)
32982							{
32983								nodes.push(this);
32984								counter = counter + 1;
32985							}
32986						}
32987
32988						if (this == endNode)
32989						{
32990							return false;
32991						}
32992
32993					});
32994
32995					var finalNodes = [];
32996					var len = nodes.length;
32997					for (var i = 0; i < len; i++)
32998					{
32999						if (nodes[i].id != 'nodes-marker-1' && nodes[i].id != 'nodes-marker-2')
33000						{
33001							finalNodes.push(nodes[i]);
33002						}
33003					}
33004
33005					this.selection.removeNodesMarkers();
33006
33007					return finalNodes;
33008
33009				},
33010				getNodesMarker: function(num)
33011				{
33012					return $('<span id="nodes-marker-' + num + '" class="redactor-nodes-marker" data-verified="redactor">' + this.opts.invisibleSpace + '</span>')[0];
33013				},
33014				setNodesMarker: function(range, node, type)
33015				{
33016					var range = range.cloneRange();
33017
33018					try {
33019						range.collapse(type);
33020						range.insertNode(node);
33021					}
33022					catch (e) {}
33023				},
33024				removeNodesMarkers: function()
33025				{
33026					$(document).find('span.redactor-nodes-marker').remove();
33027					this.$editor.find('span.redactor-nodes-marker').remove();
33028				},
33029				fromPoint: function(start, end)
33030				{
33031					this.caret.setOffset(start, end);
33032				},
33033				wrap: function(tag)
33034				{
33035					this.selection.get();
33036
33037					if (this.range.collapsed) return false;
33038
33039					var wrapper = document.createElement(tag);
33040					wrapper.appendChild(this.range.extractContents());
33041					this.range.insertNode(wrapper);
33042
33043					return wrapper;
33044				},
33045				selectElement: function(node)
33046				{
33047					if (this.utils.browser('mozilla'))
33048					{
33049						node = node[0] || node;
33050
33051						var range = document.createRange();
33052						range.selectNodeContents(node);
33053					}
33054					else
33055					{
33056						this.caret.set(node, 0, node, 1);
33057					}
33058				},
33059				selectAll: function()
33060				{
33061					this.selection.get();
33062					this.range.selectNodeContents(this.$editor[0]);
33063					this.selection.addRange();
33064				},
33065				remove: function()
33066				{
33067					this.selection.get();
33068					this.sel.removeAllRanges();
33069				},
33070				save: function()
33071				{
33072					this.selection.createMarkers();
33073				},
33074				createMarkers: function()
33075				{
33076					this.selection.get();
33077
33078					var node1 = this.selection.getMarker(1);
33079
33080					this.selection.setMarker(this.range, node1, true);
33081					if (this.range.collapsed === false)
33082					{
33083						var node2 = this.selection.getMarker(2);
33084						this.selection.setMarker(this.range, node2, false);
33085					}
33086
33087					this.savedSel = this.$editor.html();
33088				},
33089				getMarker: function(num)
33090				{
33091					if (typeof num == 'undefined') num = 1;
33092
33093					return $('<span id="selection-marker-' + num + '" class="redactor-selection-marker"  data-verified="redactor">' + this.opts.invisibleSpace + '</span>')[0];
33094				},
33095				getMarkerAsHtml: function(num)
33096				{
33097					return this.utils.getOuterHtml(this.selection.getMarker(num));
33098				},
33099				setMarker: function(range, node, type)
33100				{
33101                    var nclone = window.getSelection().getRangeAt(0).cloneRange();
33102                    range = range.cloneRange();
33103
33104					try {
33105                        var selection = window.getSelection();
33106                        range.collapse(type);
33107                        range.insertNode(node);
33108
33109                        selection.removeAllRanges();
33110                        selection.addRange(nclone);
33111
33112					}
33113					catch (e)
33114					{
33115						this.focus.setStart();
33116					}
33117
33118				},
33119				restore: function()
33120				{
33121					var node1 = this.$editor.find('span#selection-marker-1');
33122					var node2 = this.$editor.find('span#selection-marker-2');
33123
33124					if (this.utils.browser('mozilla'))
33125					{
33126						this.$editor.focus();
33127					}
33128
33129					if (node1.length !== 0 && node2.length !== 0)
33130					{
33131						this.caret.set(node1, 0, node2, 0);
33132					}
33133					else if (node1.length !== 0)
33134					{
33135						this.caret.set(node1, 0, node1, 0);
33136					}
33137					else
33138					{
33139						this.$editor.focus();
33140					}
33141
33142					this.selection.removeMarkers();
33143					this.savedSel = false;
33144
33145				},
33146				removeMarkers: function()
33147				{
33148					this.$editor.find('span.redactor-selection-marker').each(function(i,s)
33149					{
33150						var text = $(s).text().replace(/\u200B/g, '');
33151						if (text === '') $(s).remove();
33152						else $(s).replaceWith(function() { return $(this).contents(); });
33153					});
33154				},
33155				getText: function()
33156				{
33157					this.selection.get();
33158
33159					return this.sel.toString();
33160				},
33161				getHtml: function()
33162				{
33163					var html = '';
33164
33165					this.selection.get();
33166					if (this.sel.rangeCount)
33167					{
33168						var container = document.createElement('div');
33169						var len = this.sel.rangeCount;
33170						for (var i = 0; i < len; ++i)
33171						{
33172							container.appendChild(this.sel.getRangeAt(i).cloneContents());
33173						}
33174
33175						html = container.innerHTML;
33176					}
33177
33178					return this.clean.onSync(html);
33179				},
33180				replaceSelection: function(html)
33181				{
33182					this.selection.get();
33183					this.range.deleteContents();
33184					var div = document.createElement("div");
33185					div.innerHTML = html;
33186					var frag = document.createDocumentFragment(), child;
33187					while ((child = div.firstChild)) {
33188						frag.appendChild(child);
33189					}
33190
33191					this.range.insertNode(frag);
33192				},
33193				replaceWithHtml: function(html)
33194				{
33195					html = this.selection.getMarkerAsHtml(1) + html + this.selection.getMarkerAsHtml(2);
33196
33197					this.selection.get();
33198
33199					if (window.getSelection && window.getSelection().getRangeAt)
33200					{
33201						this.selection.replaceSelection(html);
33202					}
33203					else if (document.selection && document.selection.createRange)
33204					{
33205						this.range.pasteHTML(html);
33206					}
33207
33208					this.selection.restore();
33209					this.code.sync();
33210				}
33211			};
33212		},
33213		shortcuts: function()
33214		{
33215			return {
33216				init: function(e, key)
33217				{
33218					// disable browser's hot keys for bold and italic
33219					if (!this.opts.shortcuts)
33220					{
33221						if ((e.ctrlKey || e.metaKey) && (key === 66 || key === 73)) e.preventDefault();
33222						return false;
33223					}
33224
33225					$.each(this.opts.shortcuts, $.proxy(function(str, command)
33226					{
33227						var keys = str.split(',');
33228						var len = keys.length;
33229						for (var i = 0; i < len; i++)
33230						{
33231							if (typeof keys[i] === 'string')
33232							{
33233								this.shortcuts.handler(e, $.trim(keys[i]), $.proxy(function()
33234								{
33235									var func;
33236									if (command.func.search(/\./) != '-1')
33237									{
33238										func = command.func.split('.');
33239										if (typeof this[func[0]] != 'undefined')
33240										{
33241											this[func[0]][func[1]].apply(this, command.params);
33242										}
33243									}
33244									else
33245									{
33246										this[command.func].apply(this, command.params);
33247									}
33248
33249								}, this));
33250							}
33251
33252						}
33253
33254					}, this));
33255				},
33256				handler: function(e, keys, origHandler)
33257				{
33258					// based on https://github.com/jeresig/jquery.hotkeys
33259					var hotkeysSpecialKeys =
33260					{
33261						8: "backspace", 9: "tab", 10: "return", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
33262						20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
33263						37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del", 59: ";", 61: "=",
33264						96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
33265						104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
33266						112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
33267						120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 173: "-", 186: ";", 187: "=",
33268						188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'"
33269					};
33270
33271
33272					var hotkeysShiftNums =
33273					{
33274						"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
33275						"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
33276						".": ">",  "/": "?",  "\\": "|"
33277					};
33278
33279					keys = keys.toLowerCase().split(" ");
33280					var special = hotkeysSpecialKeys[e.keyCode],
33281						character = String.fromCharCode( e.which ).toLowerCase(),
33282						modif = "", possible = {};
33283
33284					$.each([ "alt", "ctrl", "meta", "shift"], function(index, specialKey)
33285					{
33286						if (e[specialKey + 'Key'] && special !== specialKey)
33287						{
33288							modif += specialKey + '+';
33289						}
33290					});
33291
33292
33293					if (special) possible[modif + special] = true;
33294					if (character)
33295					{
33296						possible[modif + character] = true;
33297						possible[modif + hotkeysShiftNums[character]] = true;
33298
33299						// "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
33300						if (modif === "shift+")
33301						{
33302							possible[hotkeysShiftNums[character]] = true;
33303						}
33304					}
33305
33306					for (var i = 0, len = keys.length; i < len; i++)
33307					{
33308						if (possible[keys[i]])
33309						{
33310							e.preventDefault();
33311							return origHandler.apply(this, arguments);
33312						}
33313					}
33314				}
33315			};
33316		},
33317		tabifier: function()
33318		{
33319			return {
33320				get: function(code)
33321				{
33322					if (!this.opts.tabifier) return code;
33323
33324					// clean setup
33325					var ownLine = ['area', 'body', 'head', 'hr', 'i?frame', 'link', 'meta', 'noscript', 'style', 'script', 'table', 'tbody', 'thead', 'tfoot'];
33326					var contOwnLine = ['li', 'dt', 'dt', 'h[1-6]', 'option', 'script'];
33327					var newLevel = ['p', 'blockquote', 'div', 'dl', 'fieldset', 'form', 'frameset', 'map', 'ol', 'pre', 'select', 'td', 'th', 'tr', 'ul'];
33328
33329					this.tabifier.lineBefore = new RegExp('^<(/?' + ownLine.join('|/?' ) + '|' + contOwnLine.join('|') + ')[ >]');
33330					this.tabifier.lineAfter = new RegExp('^<(br|/?' + ownLine.join('|/?' ) + '|/' + contOwnLine.join('|/') + ')[ >]');
33331					this.tabifier.newLevel = new RegExp('^</?(' + newLevel.join('|' ) + ')[ >]');
33332
33333					var i = 0,
33334					codeLength = code.length,
33335					point = 0,
33336					start = null,
33337					end = null,
33338					tag = '',
33339					out = '',
33340					cont = '';
33341
33342					this.tabifier.cleanlevel = 0;
33343
33344					for (; i < codeLength; i++)
33345					{
33346						point = i;
33347
33348						// if no more tags, copy and exit
33349						if (-1 == code.substr(i).indexOf( '<' ))
33350						{
33351							out += code.substr(i);
33352
33353							return this.tabifier.finish(out);
33354						}
33355
33356						// copy verbatim until a tag
33357						while (point < codeLength && code.charAt(point) != '<')
33358						{
33359							point++;
33360						}
33361
33362						if (i != point)
33363						{
33364							cont = code.substr(i, point - i);
33365							if (!cont.match(/^\s{2,}$/g))
33366							{
33367								if ('\n' == out.charAt(out.length - 1)) out += this.tabifier.getTabs();
33368								else if ('\n' == cont.charAt(0))
33369								{
33370									out += '\n' + this.tabifier.getTabs();
33371									cont = cont.replace(/^\s+/, '');
33372								}
33373
33374								out += cont;
33375							}
33376
33377							if (cont.match(/\n/)) out += '\n' + this.tabifier.getTabs();
33378						}
33379
33380						start = point;
33381
33382						// find the end of the tag
33383						while (point < codeLength && '>' != code.charAt(point))
33384						{
33385							point++;
33386						}
33387
33388						tag = code.substr(start, point - start);
33389						i = point;
33390
33391						var t;
33392
33393						if ('!--' == tag.substr(1, 3))
33394						{
33395							if (!tag.match(/--$/))
33396							{
33397								while ('-->' != code.substr(point, 3))
33398								{
33399									point++;
33400								}
33401								point += 2;
33402								tag = code.substr(start, point - start);
33403								i = point;
33404							}
33405
33406							if ('\n' != out.charAt(out.length - 1)) out += '\n';
33407
33408							out += this.tabifier.getTabs();
33409							out += tag + '>\n';
33410						}
33411						else if ('!' == tag[1])
33412						{
33413							out = this.tabifier.placeTag(tag + '>', out);
33414						}
33415						else if ('?' == tag[1])
33416						{
33417							out += tag + '>\n';
33418						}
33419						else if (t = tag.match(/^<(script|style|pre)/i))
33420						{
33421							t[1] = t[1].toLowerCase();
33422							tag = this.tabifier.cleanTag(tag);
33423							out = this.tabifier.placeTag(tag, out);
33424							end = String(code.substr(i + 1)).toLowerCase().indexOf('</' + t[1]);
33425
33426							if (end)
33427							{
33428								cont = code.substr(i + 1, end);
33429								i += end;
33430								out += cont;
33431							}
33432						}
33433						else
33434						{
33435							tag = this.tabifier.cleanTag(tag);
33436							out = this.tabifier.placeTag(tag, out);
33437						}
33438					}
33439
33440					return this.tabifier.finish(out);
33441				},
33442				getTabs: function()
33443				{
33444					var s = '';
33445					for ( var j = 0; j < this.tabifier.cleanlevel; j++ )
33446					{
33447						s += '\t';
33448					}
33449
33450					return s;
33451				},
33452				finish: function(code)
33453				{
33454					code = code.replace(/\n\s*\n/g, '\n');
33455					code = code.replace(/^[\s\n]*/, '');
33456					code = code.replace(/[\s\n]*$/, '');
33457					code = code.replace(/<script(.*?)>\n<\/script>/gi, '<script$1></script>');
33458
33459					this.tabifier.cleanlevel = 0;
33460
33461					return code;
33462				},
33463				cleanTag: function (tag)
33464				{
33465					var tagout = '';
33466					tag = tag.replace(/\n/g, ' ');
33467					tag = tag.replace(/\s{2,}/g, ' ');
33468					tag = tag.replace(/^\s+|\s+$/g, ' ');
33469
33470					var suffix = '';
33471					if (tag.match(/\/$/))
33472					{
33473						suffix = '/';
33474						tag = tag.replace(/\/+$/, '');
33475					}
33476
33477					var m;
33478					while (m = /\s*([^= ]+)(?:=((['"']).*?\3|[^ ]+))?/.exec(tag))
33479					{
33480						if (m[2]) tagout += m[1].toLowerCase() + '=' + m[2];
33481						else if (m[1]) tagout += m[1].toLowerCase();
33482
33483						tagout += ' ';
33484						tag = tag.substr(m[0].length);
33485					}
33486
33487					return tagout.replace(/\s*$/, '') + suffix + '>';
33488				},
33489				placeTag: function (tag, out)
33490				{
33491					var nl = tag.match(this.tabifier.newLevel);
33492
33493					if (tag.match(this.tabifier.lineBefore) || nl)
33494					{
33495						out = out.replace(/\s*$/, '');
33496						out += '\n';
33497					}
33498
33499					if (nl && '/' == tag.charAt(1)) this.tabifier.cleanlevel--;
33500					if ('\n' == out.charAt(out.length - 1)) out += this.tabifier.getTabs();
33501					if (nl && '/' != tag.charAt(1)) this.tabifier.cleanlevel++;
33502
33503					out += tag;
33504
33505					if (tag.match(this.tabifier.lineAfter) || tag.match(this.tabifier.newLevel))
33506					{
33507						out = out.replace(/ *$/, '');
33508						//out += '\n';
33509					}
33510
33511					return out;
33512				}
33513			};
33514		},
33515		tidy: function()
33516		{
33517			return {
33518				setupAllowed: function()
33519				{
33520					var index = $.inArray('span', this.opts.removeEmpty);
33521					if (index !== -1)
33522					{
33523						this.opts.removeEmpty.splice(index, 1);
33524					}
33525
33526					if (this.opts.allowedTags) this.opts.deniedTags = false;
33527					if (this.opts.allowedAttr) this.opts.removeAttr = false;
33528
33529					if (this.opts.linebreaks) return;
33530
33531					var tags = ['p', 'section'];
33532					if (this.opts.allowedTags) this.tidy.addToAllowed(tags);
33533					if (this.opts.deniedTags) this.tidy.removeFromDenied(tags);
33534
33535				},
33536				addToAllowed: function(tags)
33537				{
33538					var len = tags.length;
33539					for (var i = 0; i < len; i++)
33540					{
33541						if ($.inArray(tags[i], this.opts.allowedTags) == -1)
33542						{
33543							this.opts.allowedTags.push(tags[i]);
33544						}
33545					}
33546				},
33547				removeFromDenied: function(tags)
33548				{
33549					var len = tags.length;
33550					for (var i = 0; i < len; i++)
33551					{
33552						var pos = $.inArray(tags[i], this.opts.deniedTags);
33553						if (pos != -1)
33554						{
33555							this.opts.deniedTags.splice(pos, 1);
33556						}
33557					}
33558				},
33559				load: function(html, options)
33560				{
33561					this.tidy.settings = {
33562						deniedTags: this.opts.deniedTags,
33563						allowedTags: this.opts.allowedTags,
33564						removeComments: this.opts.removeComments,
33565						replaceTags: this.opts.replaceTags,
33566						replaceStyles: this.opts.replaceStyles,
33567						removeDataAttr: this.opts.removeDataAttr,
33568						removeAttr: this.opts.removeAttr,
33569						allowedAttr: this.opts.allowedAttr,
33570						removeWithoutAttr: this.opts.removeWithoutAttr,
33571						removeEmpty: this.opts.removeEmpty
33572					};
33573
33574					$.extend(this.tidy.settings, options);
33575
33576					html = this.tidy.removeComments(html);
33577
33578					// create container
33579					this.tidy.$div = $('<div />').append(html);
33580
33581					// clean
33582					this.tidy.replaceTags();
33583					this.tidy.replaceStyles();
33584					this.tidy.removeTags();
33585
33586					this.tidy.removeAttr();
33587					this.tidy.removeEmpty();
33588					this.tidy.removeParagraphsInLists();
33589					this.tidy.removeDataAttr();
33590					this.tidy.removeWithoutAttr();
33591
33592					html = this.tidy.$div.html();
33593					this.tidy.$div.remove();
33594
33595					return html;
33596				},
33597				removeComments: function(html)
33598				{
33599					if (!this.tidy.settings.removeComments) return html;
33600
33601					return html.replace(/<!--[\s\S]*?-->/gi, '');
33602				},
33603				replaceTags: function(html)
33604				{
33605					if (!this.tidy.settings.replaceTags) return html;
33606
33607					var len = this.tidy.settings.replaceTags.length;
33608					var replacement = [], rTags = [];
33609					for (var i = 0; i < len; i++)
33610					{
33611						rTags.push(this.tidy.settings.replaceTags[i][1]);
33612						replacement.push(this.tidy.settings.replaceTags[i][0]);
33613					}
33614
33615					$.each(replacement, $.proxy(function(key, value)
33616					{
33617						this.tidy.$div.find(value).replaceWith(function()
33618						{
33619							return $("<" + rTags[key] + " />", {html: $(this).html()});
33620						});
33621					}, this));
33622				},
33623				replaceStyles: function()
33624				{
33625					if (!this.tidy.settings.replaceStyles) return;
33626
33627					var len = this.tidy.settings.replaceStyles.length;
33628					this.tidy.$div.find('span').each($.proxy(function(n,s)
33629					{
33630						var $el = $(s);
33631						var style = $el.attr('style');
33632						for (var i = 0; i < len; i++)
33633						{
33634							if (style && style.match(new RegExp('^' + this.tidy.settings.replaceStyles[i][0], 'i')))
33635							{
33636								var tagName = this.tidy.settings.replaceStyles[i][1];
33637								$el.replaceWith(function()
33638								{
33639									var tag = document.createElement(tagName);
33640									return $(tag).append($(this).contents());
33641								});
33642							}
33643						}
33644
33645					}, this));
33646
33647				},
33648				removeTags: function()
33649				{
33650					if (!this.tidy.settings.deniedTags && this.tidy.settings.allowedTags)
33651					{
33652						this.tidy.$div.find('*').not(this.tidy.settings.allowedTags.join(',')).each(function(i, s)
33653						{
33654							if (s.innerHTML === '') $(s).remove();
33655							else $(s).contents().unwrap();
33656						});
33657					}
33658
33659					if (this.tidy.settings.deniedTags)
33660					{
33661						this.tidy.$div.find(this.tidy.settings.deniedTags.join(',')).each(function(i, s)
33662						{
33663							if ($(s).hasClass('redactor-script-tag') || $(s).hasClass('redactor-selection-marker')) return;
33664
33665							if (s.innerHTML === '') $(s).remove();
33666							else $(s).contents().unwrap();
33667						});
33668					}
33669				},
33670				removeAttr: function()
33671				{
33672					var len;
33673					if (!this.tidy.settings.removeAttr && this.tidy.settings.allowedAttr)
33674					{
33675
33676						var allowedAttrTags = [], allowedAttrData = [];
33677						len = this.tidy.settings.allowedAttr.length;
33678						for (var i = 0; i < len; i++)
33679						{
33680							allowedAttrTags.push(this.tidy.settings.allowedAttr[i][0]);
33681							allowedAttrData.push(this.tidy.settings.allowedAttr[i][1]);
33682						}
33683
33684
33685						this.tidy.$div.find('*').each($.proxy(function(n,s)
33686						{
33687							var $el = $(s);
33688							var pos = $.inArray($el[0].tagName.toLowerCase(), allowedAttrTags);
33689							var attributesRemove = this.tidy.removeAttrGetRemoves(pos, allowedAttrData, $el);
33690
33691							if (attributesRemove)
33692							{
33693								$.each(attributesRemove, function(z,f) {
33694									$el.removeAttr(f);
33695								});
33696							}
33697						}, this));
33698					}
33699
33700					if (this.tidy.settings.removeAttr)
33701					{
33702						len = this.tidy.settings.removeAttr.length;
33703						for (var i = 0; i < len; i++)
33704						{
33705							var attrs = this.tidy.settings.removeAttr[i][1];
33706							if ($.isArray(attrs)) attrs = attrs.join(' ');
33707
33708							this.tidy.$div.find(this.tidy.settings.removeAttr[i][0]).removeAttr(attrs);
33709						}
33710					}
33711
33712				},
33713				removeAttrGetRemoves: function(pos, allowed, $el)
33714				{
33715					var attributesRemove = [];
33716
33717					// remove all attrs
33718					if (pos == -1)
33719					{
33720						$.each($el[0].attributes, function(i, item)
33721						{
33722							attributesRemove.push(item.name);
33723						});
33724
33725					}
33726					// allow all attrs
33727					else if (allowed[pos] == '*')
33728					{
33729						attributesRemove = [];
33730					}
33731					// allow specific attrs
33732					else
33733					{
33734						$.each($el[0].attributes, function(i, item)
33735						{
33736							if ($.isArray(allowed[pos]))
33737							{
33738								if ($.inArray(item.name, allowed[pos]) == -1)
33739								{
33740									attributesRemove.push(item.name);
33741								}
33742							}
33743							else if (allowed[pos] != item.name)
33744							{
33745								attributesRemove.push(item.name);
33746							}
33747
33748						});
33749					}
33750
33751					return attributesRemove;
33752				},
33753				removeAttrs: function (el, regex)
33754				{
33755					regex = new RegExp(regex, "g");
33756					return el.each(function()
33757					{
33758						var self = $(this);
33759						var len = this.attributes.length - 1;
33760						for (var i = len; i >= 0; i--)
33761						{
33762							var item = this.attributes[i];
33763							if (item && item.specified && item.name.search(regex)>=0)
33764							{
33765								self.removeAttr(item.name);
33766							}
33767						}
33768					});
33769				},
33770				removeEmpty: function()
33771				{
33772					if (!this.tidy.settings.removeEmpty) return;
33773
33774					this.tidy.$div.find(this.tidy.settings.removeEmpty.join(',')).each(function()
33775					{
33776						var $el = $(this);
33777						var text = $el.text();
33778						text = text.replace(/\u200B/g, '');
33779						text = text.replace(/&nbsp;/gi, '');
33780						text = text.replace(/\s/g, '');
33781
33782		    	    	if (text === '' && $el.children().length === 0)
33783		    	    	{
33784			    	    	$el.remove();
33785		    	    	}
33786					});
33787				},
33788				removeParagraphsInLists: function()
33789				{
33790					this.tidy.$div.find('li p').contents().unwrap();
33791				},
33792				removeDataAttr: function()
33793				{
33794					if (!this.tidy.settings.removeDataAttr) return;
33795
33796					var tags = this.tidy.settings.removeDataAttr;
33797					if ($.isArray(this.tidy.settings.removeDataAttr)) tags = this.tidy.settings.removeDataAttr.join(',');
33798
33799					this.tidy.removeAttrs(this.tidy.$div.find(tags), '^(data-)');
33800
33801				},
33802				removeWithoutAttr: function()
33803				{
33804					if (!this.tidy.settings.removeWithoutAttr) return;
33805
33806					this.tidy.$div.find(this.tidy.settings.removeWithoutAttr.join(',')).each(function()
33807					{
33808						if (this.attributes.length === 0)
33809						{
33810							$(this).contents().unwrap();
33811						}
33812					});
33813				}
33814			};
33815		},
33816		toolbar: function()
33817		{
33818			return {
33819				init: function()
33820				{
33821					return {
33822						html:
33823						{
33824							title: this.lang.get('html'),
33825							func: 'code.toggle'
33826						},
33827						formatting:
33828						{
33829							title: this.lang.get('formatting'),
33830							dropdown:
33831							{
33832								p:
33833								{
33834									title: this.lang.get('paragraph'),
33835									func: 'block.format'
33836								},
33837								blockquote:
33838								{
33839									title: this.lang.get('quote'),
33840									func: 'block.format'
33841								},
33842								pre:
33843								{
33844									title: this.lang.get('code'),
33845									func: 'block.format'
33846								},
33847								h1:
33848								{
33849									title: this.lang.get('header1'),
33850									func: 'block.format'
33851								},
33852								h2:
33853								{
33854									title: this.lang.get('header2'),
33855									func: 'block.format'
33856								},
33857								h3:
33858								{
33859									title: this.lang.get('header3'),
33860									func: 'block.format'
33861								},
33862								h4:
33863								{
33864									title: this.lang.get('header4'),
33865									func: 'block.format'
33866								},
33867								h5:
33868								{
33869									title: this.lang.get('header5'),
33870									func: 'block.format'
33871								}
33872							}
33873						},
33874						bold:
33875						{
33876							title: this.lang.get('bold'),
33877							func: 'inline.format'
33878						},
33879						italic:
33880						{
33881							title: this.lang.get('italic'),
33882							func: 'inline.format'
33883						},
33884						deleted:
33885						{
33886							title: this.lang.get('deleted'),
33887							func: 'inline.format'
33888						},
33889						underline:
33890						{
33891							title: this.lang.get('underline'),
33892							func: 'inline.format'
33893						},
33894						unorderedlist:
33895						{
33896							title: '&bull; ' + this.lang.get('unorderedlist'),
33897							func: 'list.toggle'
33898						},
33899						orderedlist:
33900						{
33901							title: '1. ' + this.lang.get('orderedlist'),
33902							func: 'list.toggle'
33903						},
33904						outdent:
33905						{
33906							title: '< ' + this.lang.get('outdent'),
33907							func: 'indent.decrease'
33908						},
33909						indent:
33910						{
33911							title: '> ' + this.lang.get('indent'),
33912							func: 'indent.increase'
33913						},
33914						image:
33915						{
33916							title: this.lang.get('image'),
33917							func: 'image.show'
33918						},
33919						file:
33920						{
33921							title: this.lang.get('file'),
33922							func: 'file.show'
33923						},
33924						link:
33925						{
33926							title: this.lang.get('link'),
33927							dropdown:
33928							{
33929								link:
33930								{
33931									title: this.lang.get('link_insert'),
33932									func: 'link.show',
33933									observe: {
33934										element: 'a',
33935										in: {
33936											title: this.lang.get('link_edit'),
33937										},
33938										out: {
33939											title: this.lang.get('link_insert')
33940										}
33941									}
33942								},
33943								unlink:
33944								{
33945									title: this.lang.get('unlink'),
33946									func: 'link.unlink',
33947									observe: {
33948										element: 'a',
33949										out: {
33950											attr: {
33951												'class': 'redactor-dropdown-link-inactive',
33952												'aria-disabled': true
33953											}
33954										}
33955									}
33956								}
33957							}
33958						},
33959						alignment:
33960						{
33961							title: this.lang.get('alignment'),
33962							dropdown:
33963							{
33964								left:
33965								{
33966									title: this.lang.get('align_left'),
33967									func: 'alignment.left'
33968								},
33969								center:
33970								{
33971									title: this.lang.get('align_center'),
33972									func: 'alignment.center'
33973								},
33974								right:
33975								{
33976									title: this.lang.get('align_right'),
33977									func: 'alignment.right'
33978								},
33979								justify:
33980								{
33981									title: this.lang.get('align_justify'),
33982									func: 'alignment.justify'
33983								}
33984							}
33985						},
33986						horizontalrule:
33987						{
33988							title: this.lang.get('horizontalrule'),
33989							func: 'line.insert'
33990						}
33991					};
33992				},
33993				build: function()
33994				{
33995					this.toolbar.hideButtons();
33996					this.toolbar.hideButtonsOnMobile();
33997					this.toolbar.isButtonSourceNeeded();
33998
33999					if (this.opts.buttons.length === 0) return;
34000
34001					this.$toolbar = this.toolbar.createContainer();
34002
34003					this.toolbar.setOverflow();
34004					this.toolbar.append();
34005					this.toolbar.setFormattingTags();
34006					this.toolbar.loadButtons();
34007					this.toolbar.setFixed();
34008
34009					// buttons response
34010					if (this.opts.activeButtons)
34011					{
34012						this.$editor.on('mouseup.redactor keyup.redactor focus.redactor', $.proxy(this.observe.toolbar, this));
34013					}
34014
34015				},
34016				createContainer: function()
34017				{
34018					return $('<ul>').addClass('redactor-toolbar').attr({'id': 'redactor-toolbar-' + this.uuid, 'role': 'toolbar'});
34019				},
34020				setFormattingTags: function()
34021				{
34022					$.each(this.opts.toolbar.formatting.dropdown, $.proxy(function (i, s)
34023					{
34024						if ($.inArray(i, this.opts.formatting) == -1) delete this.opts.toolbar.formatting.dropdown[i];
34025					}, this));
34026
34027				},
34028				loadButtons: function()
34029				{
34030					$.each(this.opts.buttons, $.proxy(function(i, btnName)
34031					{
34032						if (!this.opts.toolbar[btnName]) return;
34033
34034						if (btnName === 'file')
34035						{
34036							 if (this.opts.fileUpload === false) return;
34037							 else if (!this.opts.fileUpload && this.opts.s3 === false) return;
34038						}
34039
34040						if (btnName === 'image')
34041						{
34042							 if (this.opts.imageUpload === false) return;
34043							 else if (!this.opts.imageUpload && this.opts.s3 === false) return;
34044						}
34045
34046						var btnObject = this.opts.toolbar[btnName];
34047						this.$toolbar.append($('<li>').append(this.button.build(btnName, btnObject)));
34048
34049					}, this));
34050				},
34051				append: function()
34052				{
34053					if (this.opts.toolbarExternal)
34054					{
34055						this.$toolbar.addClass('redactor-toolbar-external');
34056						$(this.opts.toolbarExternal).html(this.$toolbar);
34057					}
34058					else
34059					{
34060						this.$box.prepend(this.$toolbar);
34061					}
34062				},
34063				setFixed: function()
34064				{
34065					if (!this.utils.isDesktop()) return;
34066					if (this.opts.toolbarExternal) return;
34067					if (!this.opts.toolbarFixed) return;
34068
34069					this.toolbar.observeScroll();
34070					$(this.opts.toolbarFixedTarget).on('scroll.redactor.' + this.uuid, $.proxy(this.toolbar.observeScroll, this));
34071
34072				},
34073				setOverflow: function()
34074				{
34075					if (this.utils.isMobile() && this.opts.toolbarOverflow)
34076					{
34077						this.$toolbar.addClass('redactor-toolbar-overflow');
34078					}
34079				},
34080				isButtonSourceNeeded: function()
34081				{
34082					if (this.opts.source) return;
34083
34084					var index = this.opts.buttons.indexOf('html');
34085					if (index !== -1)
34086					{
34087						this.opts.buttons.splice(index, 1);
34088					}
34089				},
34090				hideButtons: function()
34091				{
34092					if (this.opts.buttonsHide.length === 0) return;
34093
34094					$.each(this.opts.buttonsHide, $.proxy(function(i, s)
34095					{
34096						var index = this.opts.buttons.indexOf(s);
34097						this.opts.buttons.splice(index, 1);
34098
34099					}, this));
34100				},
34101				hideButtonsOnMobile: function()
34102				{
34103					if (!this.utils.isMobile() || this.opts.buttonsHideOnMobile.length === 0) return;
34104
34105					$.each(this.opts.buttonsHideOnMobile, $.proxy(function(i, s)
34106					{
34107						var index = this.opts.buttons.indexOf(s);
34108						this.opts.buttons.splice(index, 1);
34109
34110					}, this));
34111				},
34112				observeScroll: function()
34113				{
34114					var scrollTop = $(this.opts.toolbarFixedTarget).scrollTop();
34115					var boxTop = 1;
34116
34117					if (this.opts.toolbarFixedTarget === document)
34118					{
34119						boxTop = this.$box.offset().top;
34120					}
34121
34122					if ((scrollTop + this.opts.toolbarFixedTopOffset) > boxTop)
34123					{
34124						this.toolbar.observeScrollEnable(scrollTop, boxTop);
34125					}
34126					else
34127					{
34128						this.toolbar.observeScrollDisable();
34129					}
34130				},
34131				observeScrollEnable: function(scrollTop, boxTop)
34132				{
34133					var top = this.opts.toolbarFixedTopOffset + scrollTop - boxTop;
34134					var left = 0;
34135					var end = boxTop + this.$box.height() - 32;
34136					var width = this.$box.innerWidth();
34137
34138					this.$toolbar.addClass('toolbar-fixed-box');
34139					this.$toolbar.css({
34140						position: 'absolute',
34141						width: width,
34142						top: top + 'px',
34143						left: left
34144					});
34145
34146					if (scrollTop > end)
34147						$('.redactor-dropdown-' + this.uuid + ':visible').hide();
34148
34149					this.toolbar.setDropdownsFixed();
34150					this.$toolbar.css('visibility', (scrollTop < end) ? 'visible' : 'hidden');
34151				},
34152				observeScrollDisable: function()
34153				{
34154					this.$toolbar.css({
34155						position: 'relative',
34156						width: 'auto',
34157						top: 0,
34158						left: 0,
34159						visibility: 'visible'
34160					});
34161
34162					this.toolbar.unsetDropdownsFixed();
34163					this.$toolbar.removeClass('toolbar-fixed-box');
34164				},
34165				setDropdownsFixed: function()
34166				{
34167					var top = this.$toolbar.innerHeight() + this.opts.toolbarFixedTopOffset;
34168					var position = 'fixed';
34169					if (this.opts.toolbarFixedTarget !== document)
34170					{
34171						top = (this.$toolbar.innerHeight() + this.$toolbar.offset().top) + this.opts.toolbarFixedTopOffset;
34172						position = 'absolute';
34173					}
34174
34175					$('.redactor-dropdown-' + this.uuid).each(function()
34176					{
34177						$(this).css({ position: position, top: top + 'px' });
34178					});
34179				},
34180				unsetDropdownsFixed: function()
34181				{
34182					var top = (this.$toolbar.innerHeight() + this.$toolbar.offset().top);
34183					$('.redactor-dropdown-' + this.uuid).each(function()
34184					{
34185						$(this).css({ position: 'absolute', top: top + 'px' });
34186					});
34187				}
34188			};
34189		},
34190		upload: function()
34191		{
34192			return {
34193				init: function(id, url, callback)
34194				{
34195					this.upload.direct = false;
34196					this.upload.callback = callback;
34197					this.upload.url = url;
34198					this.upload.$el = $(id);
34199					this.upload.$droparea = $('<div id="redactor-droparea" />');
34200
34201					this.upload.$placeholdler = $('<div id="redactor-droparea-placeholder" />').text(this.lang.get('upload_label'));
34202					this.upload.$input = $('<input type="file" name="file" />');
34203
34204					this.upload.$placeholdler.append(this.upload.$input);
34205					this.upload.$droparea.append(this.upload.$placeholdler);
34206					this.upload.$el.append(this.upload.$droparea);
34207
34208					this.upload.$droparea.off('redactor.upload');
34209					this.upload.$input.off('redactor.upload');
34210
34211					this.upload.$droparea.on('dragover.redactor.upload', $.proxy(this.upload.onDrag, this));
34212					this.upload.$droparea.on('dragleave.redactor.upload', $.proxy(this.upload.onDragLeave, this));
34213
34214					// change
34215					this.upload.$input.on('change.redactor.upload', $.proxy(function(e)
34216					{
34217						e = e.originalEvent || e;
34218						this.upload.traverseFile(this.upload.$input[0].files[0], e);
34219					}, this));
34220
34221					// drop
34222					this.upload.$droparea.on('drop.redactor.upload', $.proxy(function(e)
34223					{
34224						e.preventDefault();
34225
34226						this.upload.$droparea.removeClass('drag-hover').addClass('drag-drop');
34227						this.upload.onDrop(e);
34228
34229					}, this));
34230				},
34231				directUpload: function(file, e)
34232				{
34233					this.upload.direct = true;
34234					this.upload.traverseFile(file, e);
34235				},
34236				onDrop: function(e)
34237				{
34238					e = e.originalEvent || e;
34239					var files = e.dataTransfer.files;
34240
34241					this.upload.traverseFile(files[0], e);
34242				},
34243				traverseFile: function(file, e)
34244				{
34245					if (this.opts.s3)
34246					{
34247						this.upload.setConfig(file);
34248						this.upload.s3uploadFile(file);
34249						return;
34250					}
34251
34252					var formData = !!window.FormData ? new FormData() : null;
34253					if (window.FormData)
34254					{
34255						this.upload.setConfig(file);
34256
34257						var name = (this.upload.type == 'image') ? this.opts.imageUploadParam : this.opts.fileUploadParam;
34258						formData.append(name, file);
34259					}
34260
34261					this.progress.show();
34262					this.core.setCallback('uploadStart', e, formData);
34263					this.upload.sendData(formData, e);
34264				},
34265				setConfig: function(file)
34266				{
34267					this.upload.getType(file);
34268
34269					if (this.upload.direct)
34270					{
34271						this.upload.url = (this.upload.type == 'image') ? this.opts.imageUpload : this.opts.fileUpload;
34272						this.upload.callback = (this.upload.type == 'image') ? this.image.insert : this.file.insert;
34273					}
34274				},
34275				getType: function(file)
34276				{
34277					this.upload.type = 'image';
34278					if (this.opts.imageTypes.indexOf(file.type) == -1)
34279					{
34280						this.upload.type = 'file';
34281					}
34282
34283					if (this.opts.imageUpload === null && this.opts.fileUpload !== null)
34284					{
34285						this.upload.type = 'file';
34286					}
34287
34288				},
34289				getHiddenFields: function(obj, fd)
34290				{
34291					if (obj === false || typeof obj !== 'object') return fd;
34292
34293					$.each(obj, $.proxy(function(k, v)
34294					{
34295						if (v !== null && v.toString().indexOf('#') === 0) v = $(v).val();
34296						fd.append(k, v);
34297
34298					}, this));
34299
34300					return fd;
34301
34302				},
34303				sendData: function(formData, e)
34304				{
34305					// append hidden fields
34306					if (this.upload.type == 'image')
34307					{
34308						formData = this.upload.getHiddenFields(this.opts.uploadImageFields, formData);
34309						formData = this.upload.getHiddenFields(this.upload.imageFields, formData);
34310					}
34311					else
34312					{
34313						formData = this.upload.getHiddenFields(this.opts.uploadFileFields, formData);
34314						formData = this.upload.getHiddenFields(this.upload.fileFields, formData);
34315					}
34316
34317					var xhr = new XMLHttpRequest();
34318					xhr.open('POST', this.upload.url);
34319					xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
34320
34321					// complete
34322					xhr.onreadystatechange = $.proxy(function()
34323					{
34324					    if (xhr.readyState == 4)
34325					    {
34326					        var data = xhr.responseText;
34327
34328							data = data.replace(/^\[/, '');
34329							data = data.replace(/\]$/, '');
34330
34331							var json;
34332							try
34333							{
34334								json = (typeof data === 'string' ? $.parseJSON(data) : data);
34335							}
34336							catch(err)
34337							{
34338								json = {
34339									error: true
34340								};
34341							}
34342
34343
34344							this.progress.hide();
34345
34346							if (!this.upload.direct)
34347							{
34348								this.upload.$droparea.removeClass('drag-drop');
34349							}
34350
34351							this.upload.callback(json, this.upload.direct, e);
34352					    }
34353					}, this);
34354
34355
34356					/*
34357					xhr.upload.onprogress = $.proxy(function(e)
34358					{
34359						if (e.lengthComputable)
34360						{
34361							var complete = (e.loaded / e.total * 100 | 0);
34362							//progress.value = progress.innerHTML = complete;
34363						}
34364
34365					}, this);
34366					*/
34367
34368
34369					xhr.send(formData);
34370				},
34371				onDrag: function(e)
34372				{
34373					e.preventDefault();
34374					this.upload.$droparea.addClass('drag-hover');
34375				},
34376				onDragLeave: function(e)
34377				{
34378					e.preventDefault();
34379					this.upload.$droparea.removeClass('drag-hover');
34380				},
34381				clearImageFields: function()
34382				{
34383					this.upload.imageFields = {};
34384				},
34385				addImageFields: function(name, value)
34386				{
34387					this.upload.imageFields[name] = value;
34388				},
34389				removeImageFields: function(name)
34390				{
34391					delete this.upload.imageFields[name];
34392				},
34393				clearFileFields: function()
34394				{
34395					this.upload.fileFields = {};
34396				},
34397				addFileFields: function(name, value)
34398				{
34399					this.upload.fileFields[name] = value;
34400				},
34401				removeFileFields: function(name)
34402				{
34403					delete this.upload.fileFields[name];
34404				},
34405
34406
34407				// S3
34408				s3uploadFile: function(file)
34409				{
34410					this.upload.s3executeOnSignedUrl(file, $.proxy(function(signedURL)
34411					{
34412						this.upload.s3uploadToS3(file, signedURL);
34413					}, this));
34414				},
34415				s3executeOnSignedUrl: function(file, callback)
34416				{
34417					var xhr = new XMLHttpRequest();
34418					var mark = (this.opts.s3.search(/\?/) !== '-1') ? '?' : '&';
34419
34420					xhr.open('GET', this.opts.s3 + mark + 'name=' + file.name + '&type=' + file.type, true);
34421
34422					// Hack to pass bytes through unprocessed.
34423					if (xhr.overrideMimeType) xhr.overrideMimeType('text/plain;
34423 charset=x-user-defined');
34424
34425					var that = this;
34426					xhr.onreadystatechange = function(e)
34427					{
34428						if (this.readyState == 4 && this.status == 200)
34429						{
34430							that.progress.show();
34431							callback(decodeURIComponent(this.responseText));
34432						}
34433						else if (this.readyState == 4 && this.status != 200)
34434						{
34435							//setProgress(0, 'Could not contact signing script. Status = ' + this.status);
34436						}
34437					};
34438
34439					xhr.send();
34440				},
34441				s3createCORSRequest: function(method, url)
34442				{
34443					var xhr = new XMLHttpRequest();
34444					if ("withCredentials" in xhr)
34445					{
34446						xhr.open(method, url, true);
34447					}
34448					else if (typeof XDomainRequest != "undefined")
34449					{
34450						xhr = new XDomainRequest();
34451						xhr.open(method, url);
34452					}
34453					else
34454					{
34455						xhr = null;
34456					}
34457
34458					return xhr;
34459				},
34460				s3uploadToS3: function(file, url)
34461				{
34462					var xhr = this.upload.s3createCORSRequest('PUT', url);
34463					if (!xhr)
34464					{
34465						//setProgress(0, 'CORS not supported');
34466					}
34467					else
34468					{
34469						xhr.onload = $.proxy(function()
34470						{
34471							if (xhr.status == 200)
34472							{
34473								//setProgress(100, 'Upload completed.');
34474
34475								this.progress.hide();
34476
34477								var s3file = url.split('?');
34478
34479								if (!s3file[0])
34480								{
34481									 // url parsing is fail
34482									 return false;
34483								}
34484
34485
34486								if (!this.upload.direct)
34487								{
34488									this.upload.$droparea.removeClass('drag-drop');
34489								}
34490
34491								var json = { filelink: s3file[0] };
34492								if (this.upload.type == 'file')
34493								{
34494									var arr = s3file[0].split('/');
34495									json.filename = arr[arr.length-1];
34496								}
34497
34498								this.upload.callback(json, this.upload.direct, false);
34499
34500
34501							}
34502							else
34503							{
34504								//setProgress(0, 'Upload error: ' + xhr.status);
34505							}
34506						}, this);
34507
34508						xhr.onerror = function() {};
34509
34510						xhr.upload.onprogress = function(e) {};
34511
34512						xhr.setRequestHeader('Content-Type', file.type);
34513						xhr.setRequestHeader('x-amz-acl', 'public-read');
34514
34515						xhr.send(file);
34516					}
34517				}
34518			};
34519		},
34520		utils: function()
34521		{
34522			return {
34523				isMobile: function()
34524				{
34525					return /(iPhone|iPod|BlackBerry|Android)/.test(navigator.userAgent);
34526				},
34527				isDesktop: function()
34528				{
34529					return !/(iPhone|iPod|iPad|BlackBerry|Android)/.test(navigator.userAgent);
34530				},
34531				isString: function(obj)
34532				{
34533					return Object.prototype.toString.call(obj) == '[object String]';
34534				},
34535				isEmpty: function(html, removeEmptyTags)
34536				{
34537					html = html.replace(/[\u200B-\u200D\uFEFF]/g, '');
34538					html = html.replace(/&nbsp;/gi, '');
34539					html = html.replace(/<\/?br\s?\/?>/g, '');
34540					html = html.replace(/\s/g, '');
34541					html = html.replace(/^<p>[^\W\w\D\d]*?<\/p>$/i, '');
34542					html = html.replace(/<iframe(.*?[^>])>$/i, 'iframe');
34543					html = html.replace(/<source(.*?[^>])>$/i, 'source');
34544
34545					// remove empty tags
34546					if (removeEmptyTags !== false)
34547					{
34548						html = html.replace(/<[^\/>][^>]*><\/[^>]+>/gi, '');
34549						html = html.replace(/<[^\/>][^>]*><\/[^>]+>/gi, '');
34550					}
34551
34552					html = $.trim(html);
34553
34554					return html === '';
34555				},
34556				normalize: function(str)
34557				{
34558					if (typeof(str) === 'undefined') return 0;
34559					return parseInt(str.replace('px',''), 10);
34560				},
34561				hexToRgb: function(hex)
34562				{
34563					if (typeof hex == 'undefined') return;
34564					if (hex.search(/^#/) == -1) return hex;
34565
34566					var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
34567					hex = hex.replace(shorthandRegex, function(m, r, g, b)
34568					{
34569						return r + r + g + g + b + b;
34570					});
34571
34572					var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
34573					return 'rgb(' + parseInt(result[1], 16) + ', ' + parseInt(result[2], 16) + ', ' + parseInt(result[3], 16) + ')';
34574				},
34575				getOuterHtml: function(el)
34576				{
34577					return $('<div>').append($(el).eq(0).clone()).html();
34578				},
34579				getAlignmentElement: function(el)
34580				{
34581					if ($.inArray(el.tagName, this.opts.alignmentTags) !== -1)
34582					{
34583						return $(el);
34584					}
34585					else
34586					{
34587						return $(el).closest(this.opts.alignmentTags.toString().toLowerCase(), this.$editor[0]);
34588					}
34589				},
34590				removeEmptyAttr: function(el, attr)
34591				{
34592					var $el = $(el);
34593					if (typeof $el.attr(attr) == 'undefined')
34594					{
34595						return true;
34596					}
34597
34598					if ($el.attr(attr) === '')
34599					{
34600						$el.removeAttr(attr);
34601						return true;
34602					}
34603
34604					return false;
34605				},
34606				removeEmpty: function(i, s)
34607				{
34608					var $s = $($.parseHTML(s));
34609
34610					$s.find('.redactor-invisible-space').removeAttr('style').removeAttr('class');
34611
34612					if ($s.find('hr, br, img, iframe, source').length !== 0) return;
34613					var text = $.trim($s.text());
34614
34615					if (this.utils.isEmpty(text, false))
34616					{
34617						$s.remove();
34618					}
34619				},
34620
34621				// save and restore scroll
34622				saveScroll: function()
34623				{
34624					this.saveEditorScroll = this.$editor.scrollTop();
34625					this.saveBodyScroll = $(window).scrollTop();
34626
34627					if (this.opts.scrollTarget) this.saveTargetScroll = $(this.opts.scrollTarget).scrollTop();
34628				},
34629				restoreScroll: function()
34630				{
34631					if (typeof this.saveScroll === 'undefined' && typeof this.saveBodyScroll === 'undefined') return;
34632
34633					$(window).scrollTop(this.saveBodyScroll);
34634					this.$editor.scrollTop(this.saveEditorScroll);
34635
34636					if (this.opts.scrollTarget) $(this.opts.scrollTarget).scrollTop(this.saveTargetScroll);
34637				},
34638
34639				// get invisible space element
34640				createSpaceElement: function()
34641				{
34642					var space = document.createElement('span');
34643					space.className = 'redactor-invisible-space';
34644					space.innerHTML = this.opts.invisibleSpace;
34645
34646					return space;
34647				},
34648
34649				// replace
34650				removeInlineTags: function(node)
34651				{
34652					var tags = this.opts.inlineTags;
34653					tags.push('span');
34654
34655					if (node.tagName == 'PRE') tags.push('a');
34656
34657					$(node).find(tags.join(',')).not('span.redactor-selection-marker').contents().unwrap();
34658				},
34659				replaceWithContents: function(node, removeInlineTags)
34660				{
34661					var self = this;
34662					$(node).replaceWith(function()
34663					{
34664						if (removeInlineTags === true) self.utils.removeInlineTags(this);
34665
34666						return $(this).contents();
34667					});
34668
34669					return $(node);
34670				},
34671				replaceToTag: function(node, tag, removeInlineTags)
34672				{
34673					var replacement;
34674					var self = this;
34675					$(node).replaceWith(function()
34676					{
34677						replacement = $('<' + tag + ' />').append($(this).contents());
34678
34679						for (var i = 0; i < this.attributes.length; i++)
34680						{
34681							replacement.attr(this.attributes[i].name, this.attributes[i].value);
34682						}
34683
34684						if (removeInlineTags === true) self.utils.removeInlineTags(replacement);
34685
34686						return replacement;
34687					});
34688
34689					return replacement;
34690				},
34691
34692				// start and end of element
34693				isStartOfElement: function()
34694				{
34695					var block = this.selection.getBlock();
34696					if (!block) return false;
34697
34698					var offset = this.caret.getOffsetOfElement(block);
34699
34700					return (offset === 0) ? true : false;
34701				},
34702				isEndOfElement: function(element)
34703				{
34704					if (typeof element == 'undefined')
34705					{
34706						var element = this.selection.getBlock();
34707						if (!element) return false;
34708					}
34709
34710					var offset = this.caret.getOffsetOfElement(element);
34711					var text = $.trim($(element).text()).replace(/\n\r\n/g, '');
34712
34713					return (offset == text.length) ? true : false;
34714				},
34715				isStartOfEditor: function()
34716				{
34717					var offset = this.caret.getOffsetOfElement(this.$editor[0]);
34718
34719					return (offset === 0) ? true : false;
34720				},
34721				isEndOfEditor: function()
34722				{
34723					var block = this.$editor[0];
34724
34725					var offset = this.caret.getOffsetOfElement(block);
34726					var text = $.trim($(block).html().replace(/(<([^>]+)>)/gi,''));
34727
34728					return (offset == text.length) ? true : false;
34729				},
34730
34731				// test blocks
34732				isBlock: function(block)
34733				{
34734					block = block[0] || block;
34735
34736					return block && this.utils.isBlockTag(block.tagName);
34737				},
34738				isBlockTag: function(tag)
34739				{
34740					if (typeof tag == 'undefined') return false;
34741
34742					return this.reIsBlock.test(tag);
34743				},
34744
34745				// tag detection
34746				isTag: function(current, tag)
34747				{
34748					var element = $(current).closest(tag, this.$editor[0]);
34749					if (element.length == 1)
34750					{
34751						return element[0];
34752					}
34753
34754					return false;
34755				},
34756
34757				// select all
34758				isSelectAll: function()
34759				{
34760					return this.selectAll;
34761				},
34762				enableSelectAll: function()
34763				{
34764					this.selectAll = true;
34765				},
34766				disableSelectAll: function()
34767				{
34768					this.selectAll = false;
34769				},
34770
34771				// parents detection
34772				isRedactorParent: function(el)
34773				{
34774					if (!el)
34775					{
34776						return false;
34777					}
34778
34779					if ($(el).parents('.redactor-editor').length === 0 || $(el).hasClass('redactor-editor'))
34780					{
34781						return false;
34782					}
34783
34784					return el;
34785				},
34786				isCurrentOrParentHeader: function()
34787				{
34788					return this.utils.isCurrentOrParent(['H1', 'H2', 'H3', 'H4', 'H5', 'H6']);
34789				},
34790				isCurrentOrParent: function(tagName)
34791				{
34792					var parent = this.selection.getParent();
34793					var current = this.selection.getCurrent();
34794
34795					if ($.isArray(tagName))
34796					{
34797						var matched = 0;
34798						$.each(tagName, $.proxy(function(i, s)
34799						{
34800							if (this.utils.isCurrentOrParentOne(current, parent, s))
34801							{
34802								matched++;
34803							}
34804						}, this));
34805
34806						return (matched === 0) ? false : true;
34807					}
34808					else
34809					{
34810						return this.utils.isCurrentOrParentOne(current, parent, tagName);
34811					}
34812				},
34813				isCurrentOrParentOne: function(current, parent, tagName)
34814				{
34815					tagName = tagName.toUpperCase();
34816
34817					return parent && parent.tagName === tagName ? parent : current && current.tagName === tagName ? current : false;
34818				},
34819
34820
34821				// browsers detection
34822				isOldIe: function()
34823				{
34824					return (this.utils.browser('msie') && parseInt(this.utils.browser('version'), 10) < 9) ? true : false;
34825				},
34826				isLessIe10: function()
34827				{
34828					return (this.utils.browser('msie') && parseInt(this.utils.browser('version'), 10) < 10) ? true : false;
34829				},
34830				isIe11: function()
34831				{
34832					return !!navigator.userAgent.match(/Trident\/7\./);
34833				},
34834				browser: function(browser)
34835				{
34836					var ua = navigator.userAgent.toLowerCase();
34837					var match = /(opr)[\/]([\w.]+)/.exec( ua ) ||
34838		            /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
34839		            /(webkit)[ \/]([\w.]+).*(safari)[ \/]([\w.]+)/.exec(ua) ||
34840		            /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
34841		            /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
34842		            /(msie) ([\w.]+)/.exec( ua ) ||
34843		            ua.indexOf("trident") >= 0 && /(rv)(?::| )([\w.]+)/.exec( ua ) ||
34844		            ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
34845		            [];
34846
34847					if (browser == 'safari') return (typeof match[3] != 'undefined') ? match[3] == 'safari' : false;
34848					if (browser == 'version') return match[2];
34849					if (browser == 'webkit') return (match[1] == 'chrome' || match[1] == 'opr' || match[1] == 'webkit');
34850					if (match[1] == 'rv') return browser == 'msie';
34851					if (match[1] == 'opr') return browser == 'webkit';
34852
34853					return browser == match[1];
34854				},
34855				strpos: function(haystack, needle, offset)
34856				{
34857					var i = haystack.indexOf(needle, offset);
34858					return i >= 0 ? i : false;
34859				},
34860				disableBodyScroll: function()
34861				{
34862
34863					var $body = $('html');
34864					var windowWidth = window.innerWidth;
34865					if (!windowWidth)
34866					{
34867						var documentElementRect = document.documentElement.getBoundingClientRect();
34868						windowWidth = documentElementRect.right - Math.abs(documentElementRect.left);
34869					}
34870
34871					var isOverflowing = document.body.clientWidth < windowWidth;
34872					var scrollbarWidth = this.utils.measureScrollbar();
34873
34874					$body.css('overflow', 'hidden');
34875					if (isOverflowing) $body.css('padding-right', scrollbarWidth);
34876
34877
34878				},
34879				measureScrollbar: function()
34880				{
34881					var $body = $('body');
34882					var scrollDiv = document.createElement('div');
34883					scrollDiv.className = 'redactor-scrollbar-measure';
34884
34885					$body.append(scrollDiv);
34886					var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
34887					$body[0].removeChild(scrollDiv);
34888					return scrollbarWidth;
34889				},
34890				enableBodyScroll: function()
34891				{
34892					$('html').css({ 'overflow': '', 'padding-right': '' });
34893					$('body').remove('redactor-scrollbar-measure');
34894				}
34895			};
34896		}
34897	};
34898
34899	$(window).on('load.tools.redactor', function()
34900	{
34901		$('[data-tools="redactor"]').redactor();
34902	});
34903
34904	// constructor
34905	Redactor.prototype.init.prototype = Redactor.prototype;
34906
34907})(jQuery);
34908
34909(function($)
34910{
34911    $.Redactor.prototype.table = function()
34912    {
34913        return {
34914            getTemplate: function()
34915            {
34916                return String()
34917                    + '<section id="redactor-modal-table-insert">'
34918                    + '<label>' + this.lang.get('rows') + '</label>'
34919                    + '<input type="text" size="5" value="2" id="redactor-table-rows" />'
34920                    + '<label>' + this.lang.get('columns') + '</label>'
34921                    + '<input type="text" size="5" value="3" id="redactor-table-columns" />'
34922                    + '</section>';
34923            },
34924            init: function()
34925            {
34926                var dropdown = {};
34927
34928                dropdown.insert_table = {
34929                    title: this.lang.get('insert_table'),
34930                    func: this.table.show,
34931                    observe: {
34932                        element: 'table',
34933                        in: {
34934                            attr: {
34935                                'class': 'redactor-dropdown-link-inactive',
34936                                'aria-disabled': true,
34937                            }
34938                        }
34939                    }
34940                };
34941
34942                dropdown.insert_row_above = {
34943                    title: this.lang.get('insert_row_above'),
34944                    func: this.table.addRowAbove,
34945                    observe: {
34946                        element: 'table',
34947                        out: {
34948                            attr: {
34949                                'class': 'redactor-dropdown-link-inactive',
34950                                'aria-disabled': true,
34951                            }
34952                        }
34953                    }
34954                };
34955
34956                dropdown.insert_row_below = {
34957                    title: this.lang.get('insert_row_below'),
34958                    func: this.table.addRowBelow,
34959                    observe: {
34960                        element: 'table',
34961                        out: {
34962                            attr: {
34963                                'class': 'redactor-dropdown-link-inactive',
34964                                'aria-disabled': true,
34965                            }
34966                        }
34967                    }
34968                };
34969
34970                dropdown.insert_column_left = {
34971                    title: this.lang.get('insert_column_left'),
34972                    func: this.table.addColumnLeft,
34973                    observe: {
34974                        element: 'table',
34975                        out: {
34976                            attr: {
34977                                'class': 'redactor-dropdown-link-inactive',
34978                                'aria-disabled': true,
34979                            }
34980                        }
34981                    }
34982                };
34983
34984                dropdown.insert_column_right = {
34985                    title: this.lang.get('insert_column_right'),
34986                    func: this.table.addColumnRight,
34987                    observe: {
34988                        element: 'table',
34989                        out: {
34990                            attr: {
34991                                'class': 'redactor-dropdown-link-inactive',
34992                                'aria-disabled': true,
34993                            }
34994                        }
34995                    }
34996                };
34997
34998                dropdown.add_head = {
34999                    title: this.lang.get('add_head'),
35000                    func: this.table.addHead,
35001                    observe: {
35002                        element: 'table',
35003                        out: {
35004                            attr: {
35005                                'class': 'redactor-dropdown-link-inactive',
35006                                'aria-disabled': true,
35007                            }
35008                        }
35009                    }
35010                };
35011
35012                dropdown.delete_head = {
35013                    title: this.lang.get('delete_head'),
35014                    func: this.table.deleteHead,
35015                    observe: {
35016                        element: 'table',
35017                        out: {
35018                            attr: {
35019                                'class': 'redactor-dropdown-link-inactive',
35020                                'aria-disabled': true,
35021                            }
35022                        }
35023                    }
35024                };
35025
35026                dropdown.delete_column = {
35027                    title: this.lang.get('delete_column'),
35028                    func: this.table.deleteColumn,
35029                    observe: {
35030                        element: 'table',
35031                        out: {
35032                            attr: {
35033                                'class': 'redactor-dropdown-link-inactive',
35034                                'aria-disabled': true,
35035                            }
35036                        }
35037                    }
35038                };
35039
35040                dropdown.delete_row = {
35041                    title: this.lang.get('delete_row'),
35042                    func: this.table.deleteRow,
35043                    observe: {
35044                        element: 'table',
35045                        out: {
35046                            attr: {
35047                                'class': 'redactor-dropdown-link-inactive',
35048                                'aria-disabled': true,
35049                            }
35050                        }
35051                    }
35052                };
35053
35054                dropdown.delete_table = {
35055                    title: this.lang.get('delete_table'),
35056                    func: this.table.deleteTable,
35057                    observe: {
35058                        element: 'table',
35059                        out: {
35060                            attr: {
35061                                'class': 'redactor-dropdown-link-inactive',
35062                                'aria-disabled': true,
35063                            }
35064                        }
35065                    }
35066                };
35067
35068                this.observe.addButton('td', 'table');
35069                this.observe.addButton('th', 'table');
35070
35071                var button = this.button.add( 'table', this.lang.get('table'));
35072                this.button.addDropdown(button, dropdown);
35073            },
35074            show: function()
35075            {
35076                this.modal.addTemplate('table', this.table.getTemplate());
35077
35078                this.modal.load('table', this.lang.get('insert_table'), 300);
35079                this.modal.createCancelButton();
35080
35081                var button = this.modal.createActionButton(this.lang.get('insert'));
35082                button.on('click', this.table.insert);
35083
35084                this.selection.save();
35085                this.modal.show();
35086
35087                $('#redactor-table-rows').focus();
35088
35089            },
35090            insert: function()
35091            {
35092                this.placeholder.remove();
35093
35094                var rows = $('#redactor-table-rows').val(),
35095                    columns = $('#redactor-table-columns').val(),
35096                    $tableBox = $('<div>'),
35097                    tableId = Math.floor(Math.random() * 99999),
35098                    $table = $('<table id="table' + tableId + '"><tbody></tbody></table>'),
35099                    i, $row, z, $column;
35100
35101                for (i = 0; i < rows; i++)
35102                {
35103                    $row = $('<tr>');
35104
35105                    for (z = 0; z < columns; z++)
35106                    {
35107                        $column = $('<td>' + this.opts.invisibleSpace + '</td>');
35108
35109                        // set the focus to the first td
35110                        if (i === 0 && z === 0)
35111                        {
35112                            $column.append(this.selection.getMarker());
35113                        }
35114
35115                        $($row).append($column);
35116                    }
35117
35118                    $table.append($row);
35119                }
35120
35121                $tableBox.append($table);
35122                var html = $tableBox.html();
35123
35124                this.modal.close();
35125                this.selection.restore();
35126
35127                if (this.table.getTable()) return;
35128
35129                this.buffer.set();
35130
35131                var current = this.selection.getBlock() || this.selection.getCurrent();
35132                if (current && current.tagName != 'BODY')
35133                {
35134                    if (current.tagName == 'LI') current = $(current).closest('ul, ol');
35135                    $(current).after(html);
35136                }
35137                else
35138                {
35139                    this.insert.html(html, false);
35140                }
35141
35142                this.selection.restore();
35143
35144                var table = this.$editor.find('#table' + tableId);
35145
35146                var p = table.prev("p");
35147
35148                if (p.length > 0 && this.utils.isEmpty(p.html()))
35149                {
35150                    p.remove();
35151                }
35152
35153                if (!this.opts.linebreaks && (this.utils.browser('mozilla') || this.utils.browser('msie')))
35154                {
35155                    var $next = table.next();
35156                    if ($next.length === 0)
35157                    {
35158                        table.after(this.opts.emptyHtml);
35159                    }
35160                }
35161
35162                this.observe.buttons();
35163
35164                table.find('span.redactor-selection-marker').remove();
35165                table.removeAttr('id');
35166                console.log(table[0]);
35167                table[0].className += 'redactor-table';
35168                console.log(table[0]);
35169                this.code.sync();
35170                this.core.setCallback('insertedTable', table);
35171            },
35172            getTable: function()
35173            {
35174                var $table = $(this.selection.getParent()).closest('table');
35175
35176                if (!this.utils.isRedactorParent($table)) return false;
35177                if ($table.size() === 0) return false;
35178
35179                return $table;
35180            },
35181            restoreAfterDelete: function($table)
35182            {
35183                this.selection.restore();
35184                $table.find('span.redactor-selection-marker').remove();
35185                this.code.sync();
35186            },
35187            deleteTable: function()
35188            {
35189                var $table = this.table.getTable();
35190                if (!$table) return;
35191
35192                this.buffer.set();
35193
35194
35195                var $next = $table.next();
35196                if (!this.opts.linebreaks && $next.length !== 0)
35197                {
35198                    this.caret.setStart($next);
35199                }
35200                else
35201                {
35202                    this.caret.setAfter($table);
35203                }
35204
35205
35206                $table.remove();
35207
35208                this.code.sync();
35209            },
35210            deleteRow: function()
35211            {
35212                var $table = this.table.getTable();
35213                if (!$table) return;
35214
35215                var $current = $(this.selection.getCurrent());
35216
35217                this.buffer.set();
35218
35219                var $current_tr = $current.closest('tr');
35220                var $focus_tr = $current_tr.prev().length ? $current_tr.prev() : $current_tr.next();
35221                if ($focus_tr.length)
35222                {
35223                    var $focus_td = $focus_tr.children('td, th').first();
35224                    if ($focus_td.length) $focus_td.prepend(this.selection.getMarker());
35225                }
35226
35227                $current_tr.remove();
35228                this.table.restoreAfterDelete($table);
35229            },
35230            deleteColumn: function()
35231            {
35232                var $table = this.table.getTable();
35233                if (!$table) return;
35234
35235                this.buffer.set();
35236
35237                var $current = $(this.selection.getCurrent());
35238                var $current_td = $current.closest('td, th');
35239                var index = $current_td[0].cellIndex;
35240
35241                $table.find('tr').each($.proxy(function(i, elem)
35242                {
35243                    var $elem = $(elem);
35244                    var focusIndex = index - 1 < 0 ? index + 1 : index - 1;
35245                    if (i === 0) $elem.find('td, th').eq(focusIndex).prepend(this.selection.getMarker());
35246
35247                    $elem.find('td, th').eq(index).remove();
35248
35249                }, this));
35250
35251                this.table.restoreAfterDelete($table);
35252            },
35253            addHead: function()
35254            {
35255                var $table = this.table.getTable();
35256                if (!$table) return;
35257
35258                this.buffer.set();
35259
35260                if ($table.find('thead').size() !== 0)
35261                {
35262                    this.table.deleteHead();
35263                    return;
35264                }
35265
35266                var tr = $table.find('tr').first().clone();
35267                tr.find('td').replaceWith($.proxy(function()
35268                {
35269                    return $('<th>').html(this.opts.invisibleSpace);
35270                }, this));
35271
35272                $thead = $('<thead></thead>').append(tr);
35273                $table.prepend($thead);
35274
35275                this.code.sync();
35276
35277            },
35278            deleteHead: function()
35279            {
35280                var $table = this.table.getTable();
35281                if (!$table) return;
35282
35283                var $thead = $table.find('thead');
35284                if ($thead.size() === 0) return;
35285
35286                this.buffer.set();
35287
35288                $thead.remove();
35289                this.code.sync();
35290            },
35291            addRowAbove: function()
35292            {
35293                this.table.addRow('before');
35294            },
35295            addRowBelow: function()
35296            {
35297                this.table.addRow('after');
35298            },
35299            addColumnLeft: function()
35300            {
35301                this.table.addColumn('before');
35302            },
35303            addColumnRight: function()
35304            {
35305                this.table.addColumn('after');
35306            },
35307            addRow: function(type)
35308            {
35309                var $table = this.table.getTable();
35310                if (!$table) return;
35311
35312                this.buffer.set();
35313
35314                var $current = $(this.selection.getCurrent());
35315                var $current_tr = $current.closest('tr');
35316                var new_tr = $current_tr.clone();
35317
35318                new_tr.find('th').replaceWith(function()
35319                {
35320                    var $td = $('<td>');
35321                    $td[0].attributes = this.attributes;
35322
35323                    return $td.append($(this).contents());
35324                });
35325
35326                new_tr.find('td').html(this.opts.invisibleSpace);
35327
35328                if (type == 'after')
35329                {
35330                    $current_tr.after(new_tr);
35331                }
35332                else
35333                {
35334                    $current_tr.before(new_tr);
35335                }
35336
35337                this.code.sync();
35338            },
35339            addColumn: function (type)
35340            {
35341                var $table = this.table.getTable();
35342                if (!$table) return;
35343
35344                var index = 0;
35345                var current = $(this.selection.getCurrent());
35346
35347                this.buffer.set();
35348
35349                var $current_tr = current.closest('tr');
35350                var $current_td = current.closest('td, th');
35351
35352                $current_tr.find('td, th').each($.proxy(function(i, elem)
35353                {
35354                    if ($(elem)[0] === $current_td[0]) index = i;
35355
35356                }, this));
35357
35358                $table.find('tr').each($.proxy(function(i, elem)
35359                {
35360                    var $current = $(elem).find('td, th').eq(index);
35361
35362                    var td = $current.clone();
35363                    td.html(this.opts.invisibleSpace);
35364
35365                    if (type == 'after')
35366                    {
35367                        $current.after(td);
35368                    }
35369                    else
35370                    {
35371                        $current.before(td);
35372                    }
35373
35374                }, this));
35375
35376                this.code.sync();
35377            }
35378        };
35379    };
35380})(jQuery);
35381
35382(function($)
35383{
35384    $.Redactor.prototype.fontcolor = function()
35385    {
35386        return {
35387            init: function()
35388            {
35389                var colors = [
35390                    '#ffffff', '#000000', '#eeece1', '#1f497d', '#4f81bd', '#c0504d', '#9bbb59', '#8064a2', '#4bacc6', '#f79646', '#ffff00',
35391                    '#f2f2f2', '#7f7f7f', '#ddd9c3', '#c6d9f0', '#dbe5f1', '#f2dcdb', '#ebf1dd', '#e5e0ec', '#dbeef3', '#fdeada', '#fff2ca',
35392                    '#d8d8d8', '#595959', '#c4bd97', '#8db3e2', '#b8cce4', '#e5b9b7', '#d7e3bc', '#ccc1d9', '#b7dde8', '#fbd5b5', '#ffe694',
35393                    '#bfbfbf', '#3f3f3f', '#938953', '#548dd4', '#95b3d7', '#d99694', '#c3d69b', '#b2a2c7', '#b7dde8', '#fac08f', '#f2c314',
35394                    '#a5a5a5', '#262626', '#494429', '#17365d', '#366092', '#953734', '#76923c', '#5f497a', '#92cddc', '#e36c09', '#c09100',
35395                    '#7f7f7f', '#0c0c0c', '#1d1b10', '#0f243e', '#244061', '#632423', '#4f6128', '#3f3151', '#31859b',  '#974806', '#7f6000'
35396                ];
35397
35398                var buttons = ['fontcolor', 'backcolor'];
35399
35400                for (var i = 0; i < 2; i++)
35401                {
35402                    var name = buttons[i];
35403
35404                    var button = this.button.add(name, this.lang.get(name));
35405                    var $dropdown = this.button.addDropdown(button);
35406
35407                    $dropdown.width(242);
35408                    this.fontcolor.buildPicker($dropdown, name, colors);
35409
35410                }
35411            },
35412            buildPicker: function($dropdown, name, colors)
35413            {
35414                var rule = (name == 'backcolor') ? 'background-color' : 'color';
35415
35416                var len = colors.length;
35417                var self = this;
35418                var func = function(e)
35419                {
35420                    e.preventDefault();
35421                    self.fontcolor.set($(this).data('rule'), $(this).attr('rel'));
35422                };
35423
35424                for (var z = 0; z < len; z++)
35425                {
35426                    var color = colors[z];
35427
35428                    var $swatch = $('<a rel="' + color + '" data-rule="' + rule +'" href="#" style="float: left; font-size: 0; border: 2px solid #fff; padding: 0; margin: 0; width: 22px; height: 22px;"></a>');
35429                    $swatch.css('background-color', color);
35430                    $swatch.on('click', func);
35431
35432                    $dropdown.append($swatch);
35433                }
35434
35435                var $elNone = $('<a href="#" style="display: block; clear: both; padding: 5px; font-size: 12px; line-height: 1;"></a>').html(this.lang.get('none'));
35436                $elNone.on('click', $.proxy(function(e)
35437                {
35438                    e.preventDefault();
35439                    this.fontcolor.remove(rule);
35440
35441                }, this));
35442
35443                $dropdown.append($elNone);
35444            },
35445            set: function(rule, type)
35446            {
35447                this.inline.format('span', 'style', rule + ': ' + type + ';');
35448            },
35449            remove: function(rule)
35450            {
35451                this.inline.removeStyleRule(rule);
35452            }
35453        };
35454    };
35455})(jQuery);
35456
35457},{}]},{},[14])
35458
35459//# sourceMappingURL=app.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.