<commit_before>var
  _ = require('lodash'),
  stringify = require('json-stable-stringify'),
  Router = require('router'),
  bodyParser = require('body-parser'),
  finalhandler = require('finalhandler'),
  RequestObject = require('../core/models/requestObject'),
  ResponseObject = require('../core/models/responseObject'),
  ResponseListener = require('../core/responseListener'),
  BadRequestError = require('../core/errors/badRequestError');

module.exports = function RouterController (kuzzle) {
  this.router = null;
  this.pluginRouter = null;
  this.routename = 'kuzzle';
  this.kuzzle = kuzzle;
  this.listener = new ResponseListener(this.kuzzle, this.kuzzle.config.queues.workerWriteResponseQueue);

  /**
   * Initializes the HTTP routes for the Kuzzle REST API.
   */
  this.initRouterHttp = function () {
    var
      api = new Router(),
      coverage,
      routes = [
        {verb: 'get', url: '/_listCollections', controller: 'read', action: 'listCollections'},
        {verb: 'get', url: '/_getLastStats', controller: 'admin', action: 'getLastStats'},
        {verb: 'post', url: '/_getStats', controller: 'admin', action: 'getStats'},
        {verb: 'get', url: '/_getAllStats', controller: 'admin', action: 'getAllStats'},
        {verb: 'get', url: '/_now', controller: 'read', action: 'now'},
        {verb: 'put', url: '/_role', controller: 'admin', action: 'putRole'},
        {verb: 'get', url: '/_listSubscriptions', controller: 'subscribe', action: 'list'},
        {verb: 'get', url: '/:collection/_mapping', controller: 'admin', action: 'getMapping'},
        {verb: 'get', url: '/:collection/:id', controller: 'read', action: 'get'},
        {verb: 'post', url: '/_bulk', controller: 'bulk', action: 'import'},
        {verb: 'post', url: '/:collection/_bulk', controller: 'bulk', action: 'import'},
        {verb: 'post', url: '/:collection/_search', controller: 'read', action: 'search'},
        {verb: 'post', url: '/:collection/_count', controller: 'read', action: 'count'},
        {verb: 'post', url: '/:collection/_create', controller: 'write', action: 'create'},
        {verb: 'post', url: '/:collection', controller: 'write', action: 'publish'},
        {verb: 'delete', url: '/:collection/_query', controller: 'write', action: 'deleteByQuery'},
        {verb: 'delete', url: '/:collection/_truncate', controller: 'admin', action: 'truncateCollection'},
        {verb: 'delete', url: '/:collection/:id', controller: 'write', action: 'delete'},
        {verb: 'delete', url: '/:collection', controller: 'admin', action: 'deleteCollection'},
        {verb: 'put', url: '/:collection', controller: 'write', action: 'createCollection'},
        {verb: 'put', url: '/:collection/_mapping', controller: 'admin', action: 'putMapping'},
        {verb: 'put', url: '/:collection/:id/_:action', controller: 'write'},
        {verb: 'put', url: '/:collection/:id', controller: 'write', action: 'createOrUpdate'}
      ];
    routes = routes.concat(kuzzle.pluginsManager.routes);

    this.router = new Router();

    // create and mount a new router for the coverage API
    if (process.env.FEATURE_COVERAGE === '1') {
      coverage = require('istanbul-middleware');
      this.router.use('/coverage', coverage.createHandler({ resetOnGet: true }));
    }

    // create and mount a new router for our API
    this.router.use('/api/', api);

    // create and mount a new router for plugins
    this.pluginRouter = new Router();
    api.use('/_plugin', this.pluginRouter);

    // add a body parsing middleware to our API
    api.use(bodyParser.json());

    // Simple hello world to let know to the user that kuzzle is running
    api.get('/', function (request, response) {
      response.writeHead('Access-Control-Allow-Origin', '*');
      response.writeHead('Access-Control-Allow-Headers', 'X-Requested-With');
      response.writeHead(200, {'Content-Type': 'application/json'});
      response.end(stringify({status: 200, error: null, result: 'Hello from Kuzzle :)'}));
    });

    // Register API routes
    routes.forEach(route => {
      api[route.verb](route.url, function (request, response) {
        var params = {
          controller: route.controller
        };

        if (route.action) {
          params.action = route.action;
        }

        executeFromRest.call(kuzzle, params, request, response);
      });
    });
  };

  /**
   * Forward incoming REST requests to the HTTP routes created by the
   * initRouterHttp function.
   *
   * @param request transmitted through the REST API
   * @param response is the HTTP connection handler
   */
  this.routeHttp = function (request, response) {
    kuzzle.pluginsManager.trigger('log:silly', 'Handle HTTP request');

    this.router(request, response, finalhandler(request, response));
  };

  /**
   * Handles requests coming from websocket connections
   *
   * @param {Object} socket client
   */
  this.routeWebsocket = function (socket) {
    var
      routerCtrl = this,
      context = {
        connection: {type: 'websocket', id: socket.id},
        user: null
      };

    kuzzle.statistics.newConnection(context.connection);
    socket.on(routerCtrl.routename, function (data) {
      var
        requestObject;

      requestObject = new RequestObject(data, {}, 'websocket');

      kuzzle.pluginsManager.trigger('log:silly', 'Handle Websocket for controller ' + data.controller);
      kuzzle.router.listener.add(requestObject, context.connection);

      // Execute the funnel. Forward any non-empty response to the user.
      kuzzle.repositories.user.loadFromToken(getBearerTokenFromHeaders(data.headers))
        .then(function (user) {
          context.user = user;

          return kuzzle.funnel.execute(requestObject, context);
        })
        .then(function onExecuteSuccess (responseObject) {
          if (!_.isEmpty(responseObject)) {
            kuzzle.notifier.notify(requestObject.requestId, responseObject.toJson(), context.connection);
          }
        })
        .catch(function onExecuteError(error) {
          var errorObject = new ResponseObject({}, error);
          kuzzle.emit(requestObject.controller + ':websocket:funnel:reject', error);
          kuzzle.pluginsManager.trigger('log:error', error);
          kuzzle.notifier.notify(requestObject.requestId, errorObject.toJson(), context.connection);
        });
    });

    // handles socket disconnections
    socket.on('disconnect', function () {
      kuzzle.pluginsManager.trigger('websocket:disconnect', 'A client is disconnected');
      kuzzle.hotelClerk.removeCustomerFromAllRooms(context.connection);
      kuzzle.statistics.dropConnection(context.connection);
    });

    // handles socket crashes
    socket.on('error', function (error) {
      kuzzle.pluginsManager.trigger('websocket:error', error);
      kuzzle.hotelClerk.removeCustomerFromAllRooms(context.connection);
      kuzzle.statistics.dropConnection(context.connection);
    });
  };

  /**
   * Handles requests coming from MQ protocols: AMQP, MQTT & STOMP
   *
   */
  this.routeMQListener = function () {
    kuzzle.services.list.mqBroker.listenExchange(this.routename, function handleMQMessage(msg) {
      var
        context = {
          connection: null,
          user: null
        },
        data,
        requestObject,
        rawContent;

      if (!(msg.content instanceof Buffer)) {
        rawContent = msg.content.toString();
      }
      else {
        rawContent = (new Buffer(msg.content)).toString();
      }

      try {
        data = JSON.parse(rawContent);
      }
      catch (e) {
        kuzzle.pluginsManager.trigger('log:error', {message: 'Parse error', error: e});
        return false;
      }

      kuzzle.pluginsManager.trigger('log:silly', 'Handle MQ input' + msg.fields.routingKey);

      // For MQTT messages, we do not have a replyTo header like with AMQP or STOMP
      // => MQTT client has to send its mqtt client id and subscribe to the topic exchange mqtt.<clientId>
      //    to get feedback from Kuzzle.
      if (msg.properties && msg.properties.replyTo) {
        context.connection = {type: 'amq', id: data.clientId, replyTo: msg.properties.replyTo};
      }
      else {
        context.connection = {type: 'mqtt', id: data.clientId, replyTo: 'mqtt.' + data.clientId};
      }

      requestObject = new RequestObject(data, {}, 'mq');

      kuzzle.router.listener.add(requestObject, context.connection);
      kuzzle.repositories.user.loadFromToken(getBearerTokenFromHeaders(data.headers))
        .then(function (user) {
          context.user = user;
          return kuzzle.funnel.execute(requestObject, context);
        })
        .then(function (responseObject) {
          if (!_.isEmpty(responseObject)) {
            kuzzle.notifier.notify(requestObject.requestId, responseObject.toJson(), context.connection);
          }
        })
        .catch(function (error) {
          var errorObject = new ResponseObject({}, error);
          kuzzle.emit(requestObject.controller + ':mq:funnel:reject', error);
          kuzzle.pluginsManager.trigger('log:error', error);
          kuzzle.notifier.notify(requestObject.requestId, errorObject.toJson(), context.connection);
        });
    }); // end listenExchange
  };

};

/**
 * Transmit HTTP requests to the funnel controller and forward its response back to
 * the client
 *
 * @param params contains the request metadata
 * @param request is the original request from the client
 * @param response is the HTTP connection handler
 */
function executeFromRest(params, request, response) {
  var
    requestObject,
    errorObject,
    data,
    context;

  context = {
    connection: {type: 'rest', response: response},
    user: null
  };

  if (!params.controller) {
    errorObject = new ResponseObject({}, new BadRequestError('The "controller" argument is missing'));
    response.writeHead(errorObject.status, {'Content-Type': 'application/json'});
    response.end(stringify(errorObject.toJson()));
    return false;
  }

  if (request.headers['content-type'] && request.headers['content-type'] !== 'application/json') {
    errorObject = new ResponseObject({}, new BadRequestError('Invalid request content-type. Expected "application/json", got: "' + request.headers['content-type'] +'"'));
    response.writeHead(errorObject.status, {'Content-Type': 'application/json'});
    response.end(stringify(errorObject.toJson()));
    return false;
  }

  data = {
    controller: params.controller,
    action: params.action || request.params.action,
    collection: request.params.collection
  };

  if (request.params.action) {
    delete request.params.action;
  }
  if (request.params.collection) {
    delete request.params.collection;
  }
  if (request.params.id) {
    data._id = request.params.id;
    delete request.params.id;
  }
  _.forEach(request.params, function (value, param) {
    request.body[param] = value;
  });

  requestObject = new RequestObject(data, request.body, 'rest');

  response.setHeader('Access-Control-Allow-Origin', '*');
  response.setHeader('Access-Control-Allow-Headers', 'X-Requested-With');

  this.router.listener.add(requestObject, context.connection);

  this.repositories.user.loadFromToken(getBearerTokenFromHeaders(request.headers))
    .then(function (user) {
      context.user = user;

      return this.funnel.execute(requestObject, context);
    }.bind(this))
    .then(function (responseObject) {
      if (!_.isEmpty(responseObject)) {
        response.writeHead(responseObject.status, {'Content-Type': 'application/json'});
        response.end(stringify(responseObject.toJson()));
      }
      else {
        /*
        the controller did not respond with a valid ResponseObject,
        most likely because it deferred its treatment to a worker.
        We keep the connection open to listen to the feedback coming
        from the worker.
        */
      }
    })
    .catch(function (error) {
      errorObject = new ResponseObject({}, error);
      this.emit(requestObject.controller + ':websocket:funnel:reject', error);
      this.pluginsManager.trigger('log:error', error);
      response.writeHead(errorObject.status, {'Content-Type': 'application/json'});
      response.end(stringify(errorObject.toJson()));
    }.bind(this));
}

/**
 * Extract the Bearer token from the given headers
 * @param {Array} headers
 * @returns {*}
 */
function getBearerTokenFromHeaders (headers) {
  var
    r;

  if (headers !== undefined && headers.authorization !== undefined) {
    r = /^Bearer (.+)$/.exec(headers.authorization);
    if (r !== null && r[1].trim() !== '') {
      return r[1].trim();
    }
  }

  return null;
}
<commit_msg>rest route for admin/putRole should include the role id<commit_after>var
  _ = require('lodash'),
  stringify = require('json-stable-stringify'),
  Router = require('router'),
  bodyParser = require('body-parser'),
  finalhandler = require('finalhandler'),
  RequestObject = require('../core/models/requestObject'),
  ResponseObject = require('../core/models/responseObject'),
  ResponseListener = require('../core/responseListener'),
  BadRequestError = require('../core/errors/badRequestError');

module.exports = function RouterController (kuzzle) {
  this.router = null;
  this.pluginRouter = null;
  this.routename = 'kuzzle';
  this.kuzzle = kuzzle;
  this.listener = new ResponseListener(this.kuzzle, this.kuzzle.config.queues.workerWriteResponseQueue);

  /**
   * Initializes the HTTP routes for the Kuzzle REST API.
   */
  this.initRouterHttp = function () {
    var
      api = new Router(),
      coverage,
      routes = [
        {verb: 'get', url: '/_listCollections', controller: 'read', action: 'listCollections'},
        {verb: 'get', url: '/_getLastStats', controller: 'admin', action: 'getLastStats'},
        {verb: 'post', url: '/_getStats', controller: 'admin', action: 'getStats'},
        {verb: 'get', url: '/_getAllStats', controller: 'admin', action: 'getAllStats'},
        {verb: 'get', url: '/_now', controller: 'read', action: 'now'},
        {verb: 'put', url: '/_role/:id', controller: 'admin', action: 'putRole'},
        {verb: 'get', url: '/_listSubscriptions', controller: 'subscribe', action: 'list'},
        {verb: 'get', url: '/:collection/_mapping', controller: 'admin', action: 'getMapping'},
        {verb: 'get', url: '/:collection/:id', controller: 'read', action: 'get'},
        {verb: 'post', url: '/_bulk', controller: 'bulk', action: 'import'},
        {verb: 'post', url: '/:collection/_bulk', controller: 'bulk', action: 'import'},
        {verb: 'post', url: '/:collection/_search', controller: 'read', action: 'search'},
        {verb: 'post', url: '/:collection/_count', controller: 'read', action: 'count'},
        {verb: 'post', url: '/:collection/_create', controller: 'write', action: 'create'},
        {verb: 'post', url: '/:collection', controller: 'write', action: 'publish'},
        {verb: 'delete', url: '/:collection/_query', controller: 'write', action: 'deleteByQuery'},
        {verb: 'delete', url: '/:collection/_truncate', controller: 'admin', action: 'truncateCollection'},
        {verb: 'delete', url: '/:collection/:id', controller: 'write', action: 'delete'},
        {verb: 'delete', url: '/:collection', controller: 'admin', action: 'deleteCollection'},
        {verb: 'put', url: '/:collection', controller: 'write', action: 'createCollection'},
        {verb: 'put', url: '/:collection/_mapping', controller: 'admin', action: 'putMapping'},
        {verb: 'put', url: '/:collection/:id/_:action', controller: 'write'},
        {verb: 'put', url: '/:collection/:id', controller: 'write', action: 'createOrUpdate'}
      ];
    routes = routes.concat(kuzzle.pluginsManager.routes);

    this.router = new Router();

    // create and mount a new router for the coverage API
    if (process.env.FEATURE_COVERAGE === '1') {
      coverage = require('istanbul-middleware');
      this.router.use('/coverage', coverage.createHandler({ resetOnGet: true }));
    }

    // create and mount a new router for our API
    this.router.use('/api/', api);

    // create and mount a new router for plugins
    this.pluginRouter = new Router();
    api.use('/_plugin', this.pluginRouter);

    // add a body parsing middleware to our API
    api.use(bodyParser.json());

    // Simple hello world to let know to the user that kuzzle is running
    api.get('/', function (request, response) {
      response.writeHead('Access-Control-Allow-Origin', '*');
      response.writeHead('Access-Control-Allow-Headers', 'X-Requested-With');
      response.writeHead(200, {'Content-Type': 'application/json'});
      response.end(stringify({status: 200, error: null, result: 'Hello from Kuzzle :)'}));
    });

    // Register API routes
    routes.forEach(route => {
      api[route.verb](route.url, function (request, response) {
        var params = {
          controller: route.controller
        };

        if (route.action) {
          params.action = route.action;
        }

        executeFromRest.call(kuzzle, params, request, response);
      });
    });
  };

  /**
   * Forward incoming REST requests to the HTTP routes created by the
   * initRouterHttp function.
   *
   * @param request transmitted through the REST API
   * @param response is the HTTP connection handler
   */
  this.routeHttp = function (request, response) {
    kuzzle.pluginsManager.trigger('log:silly', 'Handle HTTP request');

    this.router(request, response, finalhandler(request, response));
  };

  /**
   * Handles requests coming from websocket connections
   *
   * @param {Object} socket client
   */
  this.routeWebsocket = function (socket) {
    var
      routerCtrl = this,
      context = {
        connection: {type: 'websocket', id: socket.id},
        user: null
      };

    kuzzle.statistics.newConnection(context.connection);
    socket.on(routerCtrl.routename, function (data) {
      var
        requestObject;

      requestObject = new RequestObject(data, {}, 'websocket');

      kuzzle.pluginsManager.trigger('log:silly', 'Handle Websocket for controller ' + data.controller);
      kuzzle.router.listener.add(requestObject, context.connection);

      // Execute the funnel. Forward any non-empty response to the user.
      kuzzle.repositories.user.loadFromToken(getBearerTokenFromHeaders(data.headers))
        .then(function (user) {
          context.user = user;

          return kuzzle.funnel.execute(requestObject, context);
        })
        .then(function onExecuteSuccess (responseObject) {
          if (!_.isEmpty(responseObject)) {
            kuzzle.notifier.notify(requestObject.requestId, responseObject.toJson(), context.connection);
          }
        })
        .catch(function onExecuteError(error) {
          var errorObject = new ResponseObject({}, error);
          kuzzle.emit(requestObject.controller + ':websocket:funnel:reject', error);
          kuzzle.pluginsManager.trigger('log:error', error);
          kuzzle.notifier.notify(requestObject.requestId, errorObject.toJson(), context.connection);
        });
    });

    // handles socket disconnections
    socket.on('disconnect', function () {
      kuzzle.pluginsManager.trigger('websocket:disconnect', 'A client is disconnected');
      kuzzle.hotelClerk.removeCustomerFromAllRooms(context.connection);
      kuzzle.statistics.dropConnection(context.connection);
    });

    // handles socket crashes
    socket.on('error', function (error) {
      kuzzle.pluginsManager.trigger('websocket:error', error);
      kuzzle.hotelClerk.removeCustomerFromAllRooms(context.connection);
      kuzzle.statistics.dropConnection(context.connection);
    });
  };

  /**
   * Handles requests coming from MQ protocols: AMQP, MQTT & STOMP
   *
   */
  this.routeMQListener = function () {
    kuzzle.services.list.mqBroker.listenExchange(this.routename, function handleMQMessage(msg) {
      var
        context = {
          connection: null,
          user: null
        },
        data,
        requestObject,
        rawContent;

      if (!(msg.content instanceof Buffer)) {
        rawContent = msg.content.toString();
      }
      else {
        rawContent = (new Buffer(msg.content)).toString();
      }

      try {
        data = JSON.parse(rawContent);
      }
      catch (e) {
        kuzzle.pluginsManager.trigger('log:error', {message: 'Parse error', error: e});
        return false;
      }

      kuzzle.pluginsManager.trigger('log:silly', 'Handle MQ input' + msg.fields.routingKey);

      // For MQTT messages, we do not have a replyTo header like with AMQP or STOMP
      // => MQTT client has to send its mqtt client id and subscribe to the topic exchange mqtt.<clientId>
      //    to get feedback from Kuzzle.
      if (msg.properties && msg.properties.replyTo) {
        context.connection = {type: 'amq', id: data.clientId, replyTo: msg.properties.replyTo};
      }
      else {
        context.connection = {type: 'mqtt', id: data.clientId, replyTo: 'mqtt.' + data.clientId};
      }

      requestObject = new RequestObject(data, {}, 'mq');

      kuzzle.router.listener.add(requestObject, context.connection);
      kuzzle.repositories.user.loadFromToken(getBearerTokenFromHeaders(data.headers))
        .then(function (user) {
          context.user = user;
          return kuzzle.funnel.execute(requestObject, context);
        })
        .then(function (responseObject) {
          if (!_.isEmpty(responseObject)) {
            kuzzle.notifier.notify(requestObject.requestId, responseObject.toJson(), context.connection);
          }
        })
        .catch(function (error) {
          var errorObject = new ResponseObject({}, error);
          kuzzle.emit(requestObject.controller + ':mq:funnel:reject', error);
          kuzzle.pluginsManager.trigger('log:error', error);
          kuzzle.notifier.notify(requestObject.requestId, errorObject.toJson(), context.connection);
        });
    }); // end listenExchange
  };

};

/**
 * Transmit HTTP requests to the funnel controller and forward its response back to
 * the client
 *
 * @param params contains the request metadata
 * @param request is the original request from the client
 * @param response is the HTTP connection handler
 */
function executeFromRest(params, request, response) {
  var
    requestObject,
    errorObject,
    data,
    context;

  context = {
    connection: {type: 'rest', response: response},
    user: null
  };

  if (!params.controller) {
    errorObject = new ResponseObject({}, new BadRequestError('The "controller" argument is missing'));
    response.writeHead(errorObject.status, {'Content-Type': 'application/json'});
    response.end(stringify(errorObject.toJson()));
    return false;
  }

  if (request.headers['content-type'] && request.headers['content-type'] !== 'application/json') {
    errorObject = new ResponseObject({}, new BadRequestError('Invalid request content-type. Expected "application/json", got: "' + request.headers['content-type'] +'"'));
    response.writeHead(errorObject.status, {'Content-Type': 'application/json'});
    response.end(stringify(errorObject.toJson()));
    return false;
  }

  data = {
    controller: params.controller,
    action: params.action || request.params.action,
    collection: request.params.collection
  };

  if (request.params.action) {
    delete request.params.action;
  }
  if (request.params.collection) {
    delete request.params.collection;
  }
  if (request.params.id) {
    data._id = request.params.id;
    delete request.params.id;
  }
  _.forEach(request.params, function (value, param) {
    request.body[param] = value;
  });

  requestObject = new RequestObject(data, request.body, 'rest');

  response.setHeader('Access-Control-Allow-Origin', '*');
  response.setHeader('Access-Control-Allow-Headers', 'X-Requested-With');

  this.router.listener.add(requestObject, context.connection);

  this.repositories.user.loadFromToken(getBearerTokenFromHeaders(request.headers))
    .then(function (user) {
      context.user = user;

      return this.funnel.execute(requestObject, context);
    }.bind(this))
    .then(function (responseObject) {
      if (!_.isEmpty(responseObject)) {
        response.writeHead(responseObject.status, {'Content-Type': 'application/json'});
        response.end(stringify(responseObject.toJson()));
      }
      else {
        /*
        the controller did not respond with a valid ResponseObject,
        most likely because it deferred its treatment to a worker.
        We keep the connection open to listen to the feedback coming
        from the worker.
        */
      }
    })
    .catch(function (error) {
      errorObject = new ResponseObject({}, error);
      this.emit(requestObject.controller + ':websocket:funnel:reject', error);
      this.pluginsManager.trigger('log:error', error);
      response.writeHead(errorObject.status, {'Content-Type': 'application/json'});
      response.end(stringify(errorObject.toJson()));
    }.bind(this));
}

/**
 * Extract the Bearer token from the given headers
 * @param {Array} headers
 * @returns {*}
 */
function getBearerTokenFromHeaders (headers) {
  var
    r;

  if (headers !== undefined && headers.authorization !== undefined) {
    r = /^Bearer (.+)$/.exec(headers.authorization);
    if (r !== null && r[1].trim() !== '') {
      return r[1].trim();
    }
  }

  return null;
}
<|endoftext|>


<commit_before>(function () {
    var multiRasterLayer,
        visibleLayers = {},
        isExternalVisible = function () {
            return true;
        },
        getItemFromLayer = function (layer) {
            var options = layer.options,
                rawProp = layer.getGmxProperties(),
                layerId = rawProp.name,
                gmx_id = Object.keys(visibleLayers).length + 1;

            return [
                gmx_id,
                gmx_id,
                options.zIndexOffset + options.zIndex,
                rawProp.styles[0].MinZoom || 1,
                rawProp.styles[0].MaxZoom || 21,
                layerId,
                layer._gmx.geometry
            ];
        },
        setVisible = function (layer, flag) {
            visibleLayers[layer.getGmxProperties().name] = layer.isExternalVisible = flag ? isExternalVisible : null;
            if (flag) { layer.onRemove(nsGmx.leafletMap); }
        };

    var addMultiRasterLayer = function (layersIds, params) {
        var map = nsGmx.leafletMap;
        if (!layersIds) { layersIds = []; }
        if (!params) { params = {}; }
        multiRasterLayer = L.gmx.createLayer({
                properties: {
                    type: 'Vector',
                    GeometryType: 'polygon',
                    identityField: 'gmx_id',
                    ZIndexField: '_zIndex',
                    attributes: ['gmx_id', '_zIndex', 'MinZoom', 'MaxZoom', 'GMX_RasterCatalogID'],
                    attrTypes: ['integer', 'integer', 'integer', 'integer', 'string'],
                    IsRasterCatalog: true,
                    RCMinZoomForRasters: 1
                }
            })
            .setFilter(function (it) {
                var zoom = map.getZoom(),
                    pArr = it.properties;
                return visibleLayers[pArr[5]] && zoom >= pArr[3] && zoom <= pArr[4];
            })
            .setStyles([
                {
                    MinZoom: 1, MaxZoom: 21,
                    DisableBalloonOnClick: true,
                    DisableBalloonOnMouseMove: true,
                    RenderStyle: {
                        weight: 0
                    },
                    HoverStyle: {
                        weight: 0
                    }
                }
            ])
            .addData(
                layersIds.reduce(function (p, layer) {
                    p.push(getItemFromLayer(layer));
                    setVisible(layer, layer._map);
                    return p;
                }, [])
            );
        if (!params.clickable || (params.clickable !== 'true' && params.clickable !== true)) { multiRasterLayer.options.clickable = false; }

        map
            .on('layeradd', function (ev) {
                var layer = ev.layer;
                if (layer instanceof L.gmx.RasterLayer) {
                    if (!(layer.getGmxProperties().name in visibleLayers)) {
                        multiRasterLayer.addData([getItemFromLayer(layer)]);
                    }
                    setVisible(layer, true);
                    multiRasterLayer.repaint();
                }
            })
            .on('layerremove', function (ev) {
                var layer = ev.layer;
                if (layer instanceof L.gmx.RasterLayer) {
                    setVisible(layer, false);
                    multiRasterLayer.repaint();
                }
            })
            .addLayer(multiRasterLayer);
    }

    var publicInterface = {
        pluginName: 'MultiRasterLayers',
        afterViewer: function (params) {
            addMultiRasterLayer(
                nsGmx.gmxMap.layers.reduce(function (p, layer) {
                    var props = layer.getGmxProperties();
                    if (props.type === 'Raster' && props.visible) { p.push(layer); }
                    return p;
                }, [])
            , params);
        },
        unload: function() {
            var map = nsGmx.leafletMap;
            map.removeLayer(multiRasterLayer);
            for (var id in visibleLayers) {
                var layer = nsGmx.gmxMap.layersByID[id];
                if (map.hasLayer(layer)) { layer.onAdd(map); }
            }
        }
    }

    window.gmxCore && window.gmxCore.addModule('MultiRasterLayers', publicInterface);
})();
<commit_msg>be happy eslint<commit_after>(function () {
    var multiRasterLayer,
        visibleLayers = {},
        isExternalVisible = function () {
            return true;
        },
        getItemFromLayer = function (layer) {
            var options = layer.options,
                rawProp = layer.getGmxProperties(),
                layerId = rawProp.name,
                gmxId = Object.keys(visibleLayers).length + 1;

            return [
                gmxId,
                gmxId,
                options.zIndexOffset + options.zIndex,
                rawProp.styles[0].MinZoom || 1,
                rawProp.styles[0].MaxZoom || 21,
                layerId,
                layer._gmx.geometry
            ];
        },
        setVisible = function (layer, flag) {
            visibleLayers[layer.getGmxProperties().name] = layer.isExternalVisible = flag ? isExternalVisible : null;
            if (flag) { layer.onRemove(nsGmx.leafletMap); }
        };

    var addMultiRasterLayer = function (layersIds, params) {
        var map = nsGmx.leafletMap;
        if (!layersIds) { layersIds = []; }
        if (!params) { params = {}; }
        multiRasterLayer = L.gmx.createLayer({
                properties: {
                    type: 'Vector',
                    GeometryType: 'polygon',
                    identityField: 'gmx_id',
                    ZIndexField: '_zIndex',
                    attributes: ['gmx_id', '_zIndex', 'MinZoom', 'MaxZoom', 'GMX_RasterCatalogID'],
                    attrTypes: ['integer', 'integer', 'integer', 'integer', 'string'],
                    IsRasterCatalog: true,
                    RCMinZoomForRasters: 1
                }
            })
            .setFilter(function (it) {
                var zoom = map.getZoom(),
                    pArr = it.properties;
                return visibleLayers[pArr[5]] && zoom >= pArr[3] && zoom <= pArr[4];
            })
            .setStyles([
                {
                    MinZoom: 1, MaxZoom: 21,
                    DisableBalloonOnClick: true,
                    DisableBalloonOnMouseMove: true,
                    RenderStyle: {
                        weight: 0
                    },
                    HoverStyle: {
                        weight: 0
                    }
                }
            ])
            .addData(
                layersIds.reduce(function (p, layer) {
                    p.push(getItemFromLayer(layer));
                    setVisible(layer, layer._map);
                    return p;
                }, [])
            );
        if (!params.clickable || (params.clickable !== 'true' && params.clickable !== true)) { multiRasterLayer.options.clickable = false; }

        map
            .on('layeradd', function (ev) {
                var layer = ev.layer;
                if (layer instanceof L.gmx.RasterLayer) {
                    if (!(layer.getGmxProperties().name in visibleLayers)) {
                        multiRasterLayer.addData([getItemFromLayer(layer)]);
                    }
                    setVisible(layer, true);
                    multiRasterLayer.repaint();
                }
            })
            .on('layerremove', function (ev) {
                var layer = ev.layer;
                if (layer instanceof L.gmx.RasterLayer) {
                    setVisible(layer, false);
                    multiRasterLayer.repaint();
                }
            })
            .addLayer(multiRasterLayer);
    };

    var publicInterface = {
        pluginName: 'MultiRasterLayers',
        afterViewer: function (params) {
            addMultiRasterLayer(
                nsGmx.gmxMap.layers.reduce(function (p, layer) {
                    var props = layer.getGmxProperties();
                    if (props.type === 'Raster' && props.visible) { p.push(layer); }
                    return p;
                }, [])
            , params);
        },
        unload: function() {
            var map = nsGmx.leafletMap;
            map.removeLayer(multiRasterLayer);
            for (var id in visibleLayers) {
                var layer = nsGmx.gmxMap.layersByID[id];
                if (map.hasLayer(layer)) { layer.onAdd(map); }
            }
        }
    };

    window.gmxCore && window.gmxCore.addModule('MultiRasterLayers', publicInterface);
})();
<|endoftext|>


<commit_before>// Import TinyMCE
import tinymce from 'tinymce/tinymce';
// Import TinyMCE theme
import 'tinymce/themes/modern/theme';
// Plugins
import 'tinymce/plugins/table';
import 'tinymce/plugins/lists';
import 'tinymce/plugins/autoresize';
import 'tinymce/plugins/link';
import 'tinymce/plugins/paste';
import 'tinymce/plugins/advlist';
// Other dependencies
import { isObject, isString } from './isType';

// Configuration extracted from https://www.tinymce.com/docs/advanced/usage-with-module-loaders/
require.context(
  'file-loader?name=./javascripts/[path][name].[ext]&context=node_modules/tinymce!tinymce/skins',
  true,
  /.*/,
);

export const defaultOptions = {
  selector: '.tinymce',
  statusbar: false,
  menubar: false,
  toolbar: 'bold italic | bullist numlist | link | table',
  plugins: 'table autoresize link paste advlist lists',
  advlist_bullet_styles: 'circle,disc,square', // Only disc bullets display on htmltoword
  target_list: false,
  autoresize_min_height: 130,
  autoresize_bottom_margin: 10,
  extended_valid_elements: 'iframe[tooltip] , a[href|target=_blank]',
  paste_auto_cleanup_on_paste: true,
  paste_remove_styles: true,
  paste_retain_style_properties: 'none',
  paste_convert_middot_lists: true,
  paste_remove_styles_if_webkit: true,
  paste_remove_spans: true,
  paste_strip_class_attributes: 'all',
  max_height: 350,
  table_default_attributes: {
    border: 1,
  },
};

export const Tinymce = {
  /*
    Initialises a tinymce editor given the object passed. If a non-valid object is passed,
    the defaultOptions object is used instead
    @param options - An object with tinyMCE properties
  */
  init(options = {}) {
    if (isObject(options)) {
      tinymce.init($.extend(true, defaultOptions, options));
    } else {
      tinymce.init(defaultOptions);
    }
  },
  /*
    Finds any tinyMCE editor whose target element/textarea has the className passed
    @param className - A string representing the class name of the tinyMCE editor
    target element/textarea to look for
    @return An Array of tinymce.Editor objects
  */
  findEditorsByClassName(className) {
    if (isString(className)) {
      return tinymce.editors.reduce((acc, e) => {
        if ($(e.getElement()).hasClass(className)) {
          return acc.concat([e]);
        }
        return acc;
      }, []);
    }
    return [];
  },
  /*
    Finds a tinyMCE editor whose target element/textarea has the id passed
    @param id - A string representing the id of the tinyMCE editor target
    element/textarea to look for
    @return tinymce.Editor object, otherwise undefined
  */
  findEditorById(id) {
    if (isString(id)) {
      return tinymce.editors.find(el => el.id === id);
    }
    return undefined;
  },
  /*
    Destroy every editor instance whose target element/textarea has the className passed. This
    method executes for each editor the method defined at tinymce.Editor.destroy (e.g. https://www.tinymce.com/docs/api/tinymce/tinymce.editor/#destroy).
    @param className - A string representing the class name of the tinyMCE editor
    target element/textarea to look for
    @return undefined
  */
  destroyEditorsByClassName(className) {
    const editors = this.findEditorsByClassName(className);
    editors.forEach(ed => ed.destroy(false));
  },
  /*
    Destroy an editor instance whose target element/textarea has HTML id passed. This method
    executes tinymce.Editor.destroy (e.g. https://www.tinymce.com/docs/api/tinymce/tinymce.editor/#destroy) for a successfull id found.
    @return undefined
  */
  destroyEditorById(id) {
    const editor = this.findEditorById(id);
    if (editor) {
      editor.destroy(false);
    }
  },
};
<commit_msg>autoresizing tinymce to min_height defined in settings. DMPRoadmap/roadmap#905<commit_after>// Import TinyMCE
import tinymce from 'tinymce/tinymce';
// Import TinyMCE theme
import 'tinymce/themes/modern/theme';
// Plugins
import 'tinymce/plugins/table';
import 'tinymce/plugins/lists';
import 'tinymce/plugins/autoresize';
import 'tinymce/plugins/link';
import 'tinymce/plugins/paste';
import 'tinymce/plugins/advlist';
// Other dependencies
import { isObject, isString } from './isType';

// Configuration extracted from https://www.tinymce.com/docs/advanced/usage-with-module-loaders/
require.context(
  'file-loader?name=./javascripts/[path][name].[ext]&context=node_modules/tinymce!tinymce/skins',
  true,
  /.*/,
);

export const defaultOptions = {
  selector: '.tinymce',
  statusbar: false,
  menubar: false,
  toolbar: 'bold italic | bullist numlist | link | table',
  plugins: 'table autoresize link paste advlist lists',
  advlist_bullet_styles: 'circle,disc,square', // Only disc bullets display on htmltoword
  target_list: false,
  autoresize_min_height: 130,
  autoresize_bottom_margin: 10,
  extended_valid_elements: 'iframe[tooltip] , a[href|target=_blank]',
  paste_auto_cleanup_on_paste: true,
  paste_remove_styles: true,
  paste_retain_style_properties: 'none',
  paste_convert_middot_lists: true,
  paste_remove_styles_if_webkit: true,
  paste_remove_spans: true,
  paste_strip_class_attributes: 'all',
  max_height: 350,
  table_default_attributes: {
    border: 1,
  },
};
/*
  This function is invoked anytime a new editor is initialised (e.g. Tinymce.init())
  and shrinks a tinymce editor to the minimum height specified at autoresize_min_height
  editor's settings. Since there are cases that tinymce editor is loaded in the DOM
  but has display:none style, the iframe associated gets the height of the screen's device
  and using this function there is no need to wait until the tinymce gains focus to be autoresized.
*/
const resizeEditors = (editors) => {
  editors.forEach((editor) => {
    $(editor.iframeElement).height(editor.settings.autoresize_min_height);
  });
};

export const Tinymce = {
  /*
    Initialises a tinymce editor given the object passed. If a non-valid object is passed,
    the defaultOptions object is used instead
    @param options - An object with tinyMCE properties
  */
  init(options = {}) {
    if (isObject(options)) {
      tinymce.init($.extend(true, defaultOptions, options)).then(resizeEditors);
    } else {
      tinymce.init(defaultOptions).then(resizeEditors);
    }
  },
  /*
    Finds any tinyMCE editor whose target element/textarea has the className passed
    @param className - A string representing the class name of the tinyMCE editor
    target element/textarea to look for
    @return An Array of tinymce.Editor objects
  */
  findEditorsByClassName(className) {
    if (isString(className)) {
      return tinymce.editors.reduce((acc, e) => {
        if ($(e.getElement()).hasClass(className)) {
          return acc.concat([e]);
        }
        return acc;
      }, []);
    }
    return [];
  },
  /*
    Finds a tinyMCE editor whose target element/textarea has the id passed
    @param id - A string representing the id of the tinyMCE editor target
    element/textarea to look for
    @return tinymce.Editor object, otherwise undefined
  */
  findEditorById(id) {
    if (isString(id)) {
      return tinymce.editors.find(el => el.id === id);
    }
    return undefined;
  },
  /*
    Destroy every editor instance whose target element/textarea has the className passed. This
    method executes for each editor the method defined at tinymce.Editor.destroy (e.g. https://www.tinymce.com/docs/api/tinymce/tinymce.editor/#destroy).
    @param className - A string representing the class name of the tinyMCE editor
    target element/textarea to look for
    @return undefined
  */
  destroyEditorsByClassName(className) {
    const editors = this.findEditorsByClassName(className);
    editors.forEach(ed => ed.destroy(false));
  },
  /*
    Destroy an editor instance whose target element/textarea has HTML id passed. This method
    executes tinymce.Editor.destroy (e.g. https://www.tinymce.com/docs/api/tinymce/tinymce.editor/#destroy) for a successfull id found.
    @return undefined
  */
  destroyEditorById(id) {
    const editor = this.findEditorById(id);
    if (editor) {
      editor.destroy(false);
    }
  },
};
<|endoftext|>


<commit_before>dojo.provide("dijit._base.manager");

dojo.declare("dijit.WidgetSet", null, {
	// summary:
	//	A set of widgets indexed by id. A default instance of this Class is
	//	available as `dijit.registry`
	//
	// example:
	//	Create a small list of widgets:
	//	|	var ws = new dijit.WidgetSet();
	//	|	ws.add(dijit.byId("one"));
	//	| 	ws.add(dijit.byId("two"));
	//	|	// destroy both:
	//	|	ws.forEach(function(w){ w.destroy(); });
	//
	// example:
	//	Using dijit.registry:
	//	|	dijit.registry.forEach(function(w){ /* do something */ });

	constructor: function(){
		this._hash = {};
	},

	add: function(/*Widget*/ widget){
		// summary: Add a widget to this list. If a duplicate ID is detected, a warning is issued.
		//
		// Widget: dijit._Widget
		//		Any dijit._Widget derrivitave.
		if(this._hash[widget.id]){
			throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered");
		}
		this._hash[widget.id]=widget;
	},

	remove: function(/*String*/ id){
		// summary: Remove a widget byID from this WidgetSet. Does not destry widget, simply
		//	removes the rerence in this list.
		delete this._hash[id];
	},

	forEach: function(/*Function*/ func){
		// summary: Iterate over this widgetSet, calling a function for each of the
		//	items.
		//
		// func:
		//		A callback function to run forEach item. Is passed a unique widget.
		//
		// exmample:
		// Using the default `dijit.registry` instance:
		// |	dijit.registry.forEach(function(widget){
		// |		console.log(widget.declaredClass);
		// |	});
		for(var id in this._hash){
			func(this._hash[id]);
		}
	},

	filter: function(/*Function*/ filter){
		// summary: Filter down this WidgetSet to a smaller new WidgetSet
		//		Works the same as `dojo.filter` and `dojo.NodeList.filter`
		//
		// filter:
		//		Callback function to test truthiness.
		//
		// example:
		//	Arbitrary: select the odd widgets in this list
		// |	var i = 0;
		// |	dijit.registry.filter(function(w){
		// |		return ++i % 2 == 0;
		// |	}).forEach(function(w){ /* odd ones */ });

		var res = new dijit.WidgetSet();
		this.forEach(function(widget){
			if(filter(widget)){ res.add(widget); }
		});
		return res; // dijit.WidgetSet
	},

	byId: function(/*String*/ id){
		// summary: Find a widget in this list byId.
		//
		// example:
		//	As a synonym for `dijit.byId`:
		// | dijit.registry.byId("foo");
		//
		// example:
		//	Test if an id is in a particular WidgetSet
		//	| var ws = new dijit.WidgetSet();
		//	| ws.add(dijit.byId("bar"));
		//	| var t = ws.byId("bar") // returns a widget
		//	| var x = ws.byId("foo"); // returns undefined

		return this._hash[id];
	},

	byClass: function(/*String*/ cls){
		// summary: Reduce this widgetset to a new WidgetSet of a particular declaredClass
		//
		// example:
		// Find all titlePane's in a page:
		// |	dijit.registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); });

		return this.filter(function(widget){ return widget.declaredClass==cls; });	// dijit.WidgetSet
	}

});

/*=====
dijit.registry = {
	// summary: A list of widgets on a page.
	// description: Is an instance of `dijit.WidgetSet`
};
=====*/
dijit.registry = new dijit.WidgetSet();

dijit._widgetTypeCtr = {};

dijit.getUniqueId = function(/*String*/widgetType){
	// summary: Generates a unique id for a given widgetType

	var id;
	do{
		id = widgetType + "_" +
			(widgetType in dijit._widgetTypeCtr ?
				++dijit._widgetTypeCtr[widgetType] : dijit._widgetTypeCtr[widgetType] = 0);
	}while(dijit.byId(id));
	return id; // String
};

if(dojo.isIE){
	// Only run this for IE because we think it's only necessary in that case,
	// and because it causes problems on FF.  See bug #3531 for details.
	dojo.addOnWindowUnload(function(){
		dijit.registry.forEach(function(widget){ widget.destroy(); });
	});
}

dijit.byId = function(/*String|Widget*/id){
	// summary:
	//		Returns a widget by its id, or if passed a widget, no-op (like dojo.byId())
	return (dojo.isString(id)) ? dijit.registry.byId(id) : id; // Widget
};

dijit.byNode = function(/* DOMNode */ node){
	// summary:
	//		Returns the widget as referenced by node
	return dijit.registry.byId(node.getAttribute("widgetId")); // Widget
};

dijit.getEnclosingWidget = function(/* DOMNode */ node){
	// summary:
	//		Returns the widget whose dom tree contains node or null if
	//		the node is not contained within the dom tree of any widget
	while(node){
		if(node.getAttribute && node.getAttribute("widgetId")){
			return dijit.registry.byId(node.getAttribute("widgetId"));
		}
		node = node.parentNode;
	}
	return null;
};

// elements that are tab-navigable if they have no tabindex value set
// (except for "a", which must have an href attribute)
dijit._tabElements = {
	area: true,
	button: true,
	input: true,
	object: true,
	select: true,
	textarea: true
};

dijit._isElementShown = function(/*Element*/elem){
	var style = dojo.style(elem);
	return (style.visibility != "hidden")
		&& (style.visibility != "collapsed")
		&& (style.display != "none")
		&& (dojo.attr(elem, "type") != "hidden");
}

dijit.isTabNavigable = function(/*Element*/elem){
	// summary:
	//		Tests if an element is tab-navigable
	if(dojo.hasAttr(elem, "disabled")){ return false; }
	var hasTabindex = dojo.hasAttr(elem, "tabindex");
	var tabindex = dojo.attr(elem, "tabindex");
	if(hasTabindex && tabindex >= 0) {
		return true; // boolean
	}
	var name = elem.nodeName.toLowerCase();
	if(((name == "a" && dojo.hasAttr(elem, "href"))
			|| dijit._tabElements[name])
		&& (!hasTabindex || tabindex >= 0)){
		return true; // boolean
	}
	return false; // boolean
};

dijit._getTabNavigable = function(/*DOMNode*/root){
	// summary:
	//		Finds descendants of the specified root node.
	//
	// description:
	//		Finds the following descendants of the specified root node:
	//		* the first tab-navigable element in document order
	//		  without a tabindex or with tabindex="0"
	//		* the last tab-navigable element in document order
	//		  without a tabindex or with tabindex="0"
	//		* the first element in document order with the lowest
	//		  positive tabindex value
	//		* the last element in document order with the highest
	//		  positive tabindex value
	var first, last, lowest, lowestTabindex, highest, highestTabindex;
	var walkTree = function(/*DOMNode*/parent){
		dojo.query("> *", parent).forEach(function(child){
			var isShown = dijit._isElementShown(child);
			if(isShown && dijit.isTabNavigable(child)){
				var tabindex = dojo.attr(child, "tabindex");
				if(!dojo.hasAttr(child, "tabindex") || tabindex == 0){
					if(!first){ first = child; }
					last = child;
				}else if(tabindex > 0){
					if(!lowest || tabindex < lowestTabindex){
						lowestTabindex = tabindex;
						lowest = child;
					}
					if(!highest || tabindex >= highestTabindex){
						highestTabindex = tabindex;
						highest = child;
					}
				}
			}
			if(isShown && child.nodeName.toUpperCase() != 'SELECT'){ walkTree(child) }
		});
	};
	if(dijit._isElementShown(root)){ walkTree(root) }
	return { first: first, last: last, lowest: lowest, highest: highest };
}
dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/root){
	// summary:
	//		Finds the descendant of the specified root node
	//		that is first in the tabbing order
	var elems = dijit._getTabNavigable(dojo.byId(root));
	return elems.lowest ? elems.lowest : elems.first; // Element
};

dijit.getLastInTabbingOrder = function(/*String|DOMNode*/root){
	// summary:
	//		Finds the descendant of the specified root node
	//		that is last in the tabbing order
	var elems = dijit._getTabNavigable(dojo.byId(root));
	return elems.last ? elems.last : elems.highest; // Element
};

// dijit.defaultDuration
//	Default duration for wipe and fade animations within dijits
dijit.defaultDuration = dojo.config["defaultDuration"] || 200;<commit_msg>refs #7461 - forcing fix of jsdoc mixin bug. mixing in defaultDuration into dijit so it gets documented (in a pseudo-block)<commit_after>dojo.provide("dijit._base.manager");

dojo.declare("dijit.WidgetSet", null, {
	// summary:
	//	A set of widgets indexed by id. A default instance of this Class is
	//	available as `dijit.registry`
	//
	// example:
	//	Create a small list of widgets:
	//	|	var ws = new dijit.WidgetSet();
	//	|	ws.add(dijit.byId("one"));
	//	| 	ws.add(dijit.byId("two"));
	//	|	// destroy both:
	//	|	ws.forEach(function(w){ w.destroy(); });
	//
	// example:
	//	Using dijit.registry:
	//	|	dijit.registry.forEach(function(w){ /* do something */ });

	constructor: function(){
		this._hash = {};
	},

	add: function(/*Widget*/ widget){
		// summary: Add a widget to this list. If a duplicate ID is detected, a warning is issued.
		//
		// Widget: dijit._Widget
		//		Any dijit._Widget derrivitave.
		if(this._hash[widget.id]){
			throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered");
		}
		this._hash[widget.id]=widget;
	},

	remove: function(/*String*/ id){
		// summary: Remove a widget byID from this WidgetSet. Does not destry widget, simply
		//	removes the rerence in this list.
		delete this._hash[id];
	},

	forEach: function(/*Function*/ func){
		// summary: Iterate over this widgetSet, calling a function for each of the
		//	items.
		//
		// func:
		//		A callback function to run forEach item. Is passed a unique widget.
		//
		// exmample:
		// Using the default `dijit.registry` instance:
		// |	dijit.registry.forEach(function(widget){
		// |		console.log(widget.declaredClass);
		// |	});
		for(var id in this._hash){
			func(this._hash[id]);
		}
	},

	filter: function(/*Function*/ filter){
		// summary: Filter down this WidgetSet to a smaller new WidgetSet
		//		Works the same as `dojo.filter` and `dojo.NodeList.filter`
		//
		// filter:
		//		Callback function to test truthiness.
		//
		// example:
		//	Arbitrary: select the odd widgets in this list
		// |	var i = 0;
		// |	dijit.registry.filter(function(w){
		// |		return ++i % 2 == 0;
		// |	}).forEach(function(w){ /* odd ones */ });

		var res = new dijit.WidgetSet();
		this.forEach(function(widget){
			if(filter(widget)){ res.add(widget); }
		});
		return res; // dijit.WidgetSet
	},

	byId: function(/*String*/ id){
		// summary: Find a widget in this list byId.
		//
		// example:
		//	As a synonym for `dijit.byId`:
		// | dijit.registry.byId("foo");
		//
		// example:
		//	Test if an id is in a particular WidgetSet
		//	| var ws = new dijit.WidgetSet();
		//	| ws.add(dijit.byId("bar"));
		//	| var t = ws.byId("bar") // returns a widget
		//	| var x = ws.byId("foo"); // returns undefined

		return this._hash[id];
	},

	byClass: function(/*String*/ cls){
		// summary: Reduce this widgetset to a new WidgetSet of a particular declaredClass
		//
		// example:
		// Find all titlePane's in a page:
		// |	dijit.registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); });

		return this.filter(function(widget){ return widget.declaredClass==cls; });	// dijit.WidgetSet
	}

});

/*=====
dijit.registry = {
	// summary: A list of widgets on a page.
	// description: Is an instance of `dijit.WidgetSet`
};
=====*/
dijit.registry = new dijit.WidgetSet();

dijit._widgetTypeCtr = {};

dijit.getUniqueId = function(/*String*/widgetType){
	// summary: Generates a unique id for a given widgetType

	var id;
	do{
		id = widgetType + "_" +
			(widgetType in dijit._widgetTypeCtr ?
				++dijit._widgetTypeCtr[widgetType] : dijit._widgetTypeCtr[widgetType] = 0);
	}while(dijit.byId(id));
	return id; // String
};

if(dojo.isIE){
	// Only run this for IE because we think it's only necessary in that case,
	// and because it causes problems on FF.  See bug #3531 for details.
	dojo.addOnWindowUnload(function(){
		dijit.registry.forEach(function(widget){ widget.destroy(); });
	});
}

dijit.byId = function(/*String|Widget*/id){
	// summary:
	//		Returns a widget by its id, or if passed a widget, no-op (like dojo.byId())
	return (dojo.isString(id)) ? dijit.registry.byId(id) : id; // Widget
};

dijit.byNode = function(/* DOMNode */ node){
	// summary:
	//		Returns the widget as referenced by node
	return dijit.registry.byId(node.getAttribute("widgetId")); // Widget
};

dijit.getEnclosingWidget = function(/* DOMNode */ node){
	// summary:
	//		Returns the widget whose dom tree contains node or null if
	//		the node is not contained within the dom tree of any widget
	while(node){
		if(node.getAttribute && node.getAttribute("widgetId")){
			return dijit.registry.byId(node.getAttribute("widgetId"));
		}
		node = node.parentNode;
	}
	return null;
};

// elements that are tab-navigable if they have no tabindex value set
// (except for "a", which must have an href attribute)
dijit._tabElements = {
	area: true,
	button: true,
	input: true,
	object: true,
	select: true,
	textarea: true
};

dijit._isElementShown = function(/*Element*/elem){
	var style = dojo.style(elem);
	return (style.visibility != "hidden")
		&& (style.visibility != "collapsed")
		&& (style.display != "none")
		&& (dojo.attr(elem, "type") != "hidden");
}

dijit.isTabNavigable = function(/*Element*/elem){
	// summary:
	//		Tests if an element is tab-navigable
	if(dojo.hasAttr(elem, "disabled")){ return false; }
	var hasTabindex = dojo.hasAttr(elem, "tabindex");
	var tabindex = dojo.attr(elem, "tabindex");
	if(hasTabindex && tabindex >= 0) {
		return true; // boolean
	}
	var name = elem.nodeName.toLowerCase();
	if(((name == "a" && dojo.hasAttr(elem, "href"))
			|| dijit._tabElements[name])
		&& (!hasTabindex || tabindex >= 0)){
		return true; // boolean
	}
	return false; // boolean
};

dijit._getTabNavigable = function(/*DOMNode*/root){
	// summary:
	//		Finds descendants of the specified root node.
	//
	// description:
	//		Finds the following descendants of the specified root node:
	//		* the first tab-navigable element in document order
	//		  without a tabindex or with tabindex="0"
	//		* the last tab-navigable element in document order
	//		  without a tabindex or with tabindex="0"
	//		* the first element in document order with the lowest
	//		  positive tabindex value
	//		* the last element in document order with the highest
	//		  positive tabindex value
	var first, last, lowest, lowestTabindex, highest, highestTabindex;
	var walkTree = function(/*DOMNode*/parent){
		dojo.query("> *", parent).forEach(function(child){
			var isShown = dijit._isElementShown(child);
			if(isShown && dijit.isTabNavigable(child)){
				var tabindex = dojo.attr(child, "tabindex");
				if(!dojo.hasAttr(child, "tabindex") || tabindex == 0){
					if(!first){ first = child; }
					last = child;
				}else if(tabindex > 0){
					if(!lowest || tabindex < lowestTabindex){
						lowestTabindex = tabindex;
						lowest = child;
					}
					if(!highest || tabindex >= highestTabindex){
						highestTabindex = tabindex;
						highest = child;
					}
				}
			}
			if(isShown && child.nodeName.toUpperCase() != 'SELECT'){ walkTree(child) }
		});
	};
	if(dijit._isElementShown(root)){ walkTree(root) }
	return { first: first, last: last, lowest: lowest, highest: highest };
}
dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/root){
	// summary:
	//		Finds the descendant of the specified root node
	//		that is first in the tabbing order
	var elems = dijit._getTabNavigable(dojo.byId(root));
	return elems.lowest ? elems.lowest : elems.first; // DomNode
};

dijit.getLastInTabbingOrder = function(/*String|DOMNode*/root){
	// summary:
	//		Finds the descendant of the specified root node
	//		that is last in the tabbing order
	var elems = dijit._getTabNavigable(dojo.byId(root));
	return elems.last ? elems.last : elems.highest; // DomNode
};

/*=====
dojo.mixin(dijit, {
	// defaultDuration: Integer
	//		The default animation speed (in ms) to use for all Dijit
	//		transitional animations, unless otherwise specified
	//		on a per-instance basis. Defaults to 200, overrided by
	//		`djConfig.defaultDuration`
	defaultDuration: 300
});
=====*/

dijit.defaultDuration = dojo.config["defaultDuration"] || 200;<|endoftext|>


<commit_before>var SF = SF || {};

SF.Widgets = (function () {
    $(".sf-widget").live("mouseover mouseout", function (evt) {
        var $this = $(this);
        if (evt.type == "mouseover") {
            SF.Dropdowns.toggle(event, this);
            var $content = $this.find(".sf-widget-content");
            $content.css({
                top: $this.height() + 8, /*8 = .sf-widget padding-top + padding-bottom*/
                left: ($this.width() - $content.width())
            });
        }
        else {
            SF.Dropdowns.toggle(event, this);
        }
    });
})();<commit_msg>QuickLinks firefox fix<commit_after>var SF = SF || {};

SF.Widgets = (function () {
    $(".sf-widget").live("mouseover mouseout", function (evt) {
        var $this = $(this);
        if (evt.type == "mouseover") {
            SF.Dropdowns.toggle(evt, this);
            var $content = $this.find(".sf-widget-content");
            $content.css({
                top: $this.height() + 8, /*8 = .sf-widget padding-top + padding-bottom*/
                left: ($this.width() - $content.width())
            });
        }
        else {
            SF.Dropdowns.toggle(evt, this);
        }
    });
})();<|endoftext|>


<commit_before>// does not work when this methods are not instantiated before, don't know why
_.each(Template, function (template, templateName) {
    if (template.kind === 'Template_' + templateName) {
        Template[templateName].created = function () {};
        Template[templateName].rendered = function () {};
        Template[templateName].destroyed = function () {};
    }
});

Template.created = function (template_name, callback) {
    var _base;
    this._created_callbacks || (this._created_callbacks = {});
    (_base = this._created_callbacks)[template_name] || (_base[template_name] = []);
    return this._created_callbacks[template_name].push(callback);
};

Template.bootstrapCreatedCallbacks = function () {
    return _.each(this, function (template, templateName) {
        if (template.kind === 'Template_' + templateName) {
            var superFunction = Template[templateName].created;

            return Template[templateName].created = function () {
                var self;
                superFunction();
                return _.each(_.union(Template._created_callbacks[templateName], Template._created_callbacks[null]), function (func) {
                    return func && func.bind(self)();
                });
            };
        }
    });
};

Template.rendered = function (template_name, callback) {
    var _base;
    this._rendered_callbacks || (this._rendered_callbacks = {});
    (_base = this._rendered_callbacks)[template_name] || (_base[template_name] = []);
    return this._rendered_callbacks[template_name].push(callback);
};

Template.bootstrapRenderedCallbacks = function () {
    return _.each(this, function (template, templateName) {
        if (template.kind === 'Template_' + templateName) {
            var superFunction = Template[templateName].rendered;

            return Template[templateName].rendered = function () {
                var self;
                superFunction();
                return _.each(_.union(Template._rendered_callbacks[templateName], Template._rendered_callbacks[null]), function (func) {
                    return func && func.bind(self)();
                });
            };
        }
    });
};

Template.destroyed = function (template_name, callback) {
    var _base;
    this._destroyed_callbacks || (this._destroyed_callbacks = {});
    (_base = this._destroyed_callbacks)[template_name] || (_base[template_name] = []);
    return this._destroyed_callbacks[template_name].push(callback);
};

Template.bootstrapDestroyedCallbacks = function () {
    return _.each(this, function (template, templateName) {
        if (template.kind === 'Template_' + templateName) {
            var superFunction = Template[templateName].destroyed;

            return Template[templateName].destroyed = function () {
                var self;
                superFunction();
                return _.each(_.union(Template._destroyed_callbacks[templateName], Template._destroyed_callbacks[null]), function (func) {
                    return func && func.bind(self)();
                });
            };
        }
    });
};

Meteor.startup(function () {
    Template.bootstrapCreatedCallbacks();
    Template.bootstrapRenderedCallbacks();
    Template.bootstrapDestroyedCallbacks();
});<commit_msg>Smaller version<commit_after>var eventNames = ['created', 'rendered', 'destroyed'];
var methodNames = ['Created', 'Rendered', 'Destroyed'];

// does not work when this methods are not instantiated before, don't know why
_.each(Template, function(template, templateName) {
    if (template.kind === 'Template_' + templateName) {
        _.each(eventNames, function(eventName) {
            Template[templateName][eventName] = function() {};
        });
    }
});

_.each(eventNames, function(eventName, i) {
    Template[eventName] = function(template_name, callback) {
        var _base;
        this['_' + eventName + '_callbacks'] || (this['_' + eventName + '_callbacks'] = {});
        (_base = this['_' + eventName + '_callbacks'])[template_name] || (_base[template_name] = []);
        return this['_' + eventName + '_callbacks'][template_name].push(callback);
    };

    Template['bootstrap' + methodNames[i] + 'Callbacks'] = function() {
        return _.each(this, function(template, templateName) {
            if (template.kind === 'Template_' + templateName) {
                var superFunction = Template[templateName][eventName];

                return Template[templateName][eventName] = function() {
                    var self;
                    superFunction();
                    return _.each(_.union(Template['_' + eventName + '_callbacks'][templateName], Template['_' + eventName + '_callbacks'][null]), function(func) {
                        return func && func.bind(self)();
                    });
                };
            }
        });
    };
});

Meteor.startup(function() {
    Template.bootstrapCreatedCallbacks();
    Template.bootstrapRenderedCallbacks();
    Template.bootstrapDestroyedCallbacks();
});<|endoftext|>


<commit_before>$(function() {
	$("#loginForm").submit(function(event) {
		event.preventDefault();
		var $form = $(this);
		var $submitButton = $form.find("[type=submit]");

		$submitButton.attr("disabled", true);
		$form.css({
			"transform": "perspective(512px) rotateX(-90deg)",
			"opacity": "0",
			"transition": "all ease-in 0.5s"
		});

		$.ajax({
			url: $form.attr("action"),
			type: $form.attr("method"),
			data: $form.serialize()
		}).done(function() {
			location.reload();
		}).fail(function() {
			$submitButton.attr("disabled", false);
			setTimeout(function() {
				$form.css({
					"transform": "perspective(512px) scale(1)",
					"opacity": "1",
					"transition": "all ease 0.7s"
				});
			}, 500);
		});
	});

	$('#new').click(function() {
		showRegisterForm();
	});

	initRegisterForm();

	$('#name').keyup(function() {
		$("#nameAvailable").remove();
		var name = $('#name').val();
		if (name.length == 0) {
			return false;
		}
		$('#name').before('
Great!
');
	});

	$('#password').keyup(function() {
		$("#passwordAvailable").remove();
		var password = $('#password').val();
		if (password.length == 0) {
			return false;
		}
		if (password.length < 8) {
			$('#password').before('
8文字以上でお願いします
');
			return false;
		}
		$('#password').before('
Nice!
');
	});

	$('#passwordRetype').keyup(function() {
		$("#passwordRetypeAvailable").remove();
		var password = $('#password').val();
		var passwordRetype = $('#passwordRetype').val();
		if (passwordRetype.length == 0) {
			return false;
		}
		if (passwordRetype != password) {
			$('#passwordRetype').before('
一致していませんっ
');
			return false;
		}
		$('#passwordRetype').before('
Okay!
');
	});

	$('#color').change(function() {
		$("#colorAvailable").remove();
		var color = $('#color').val();
		$('#color').before('
Good!
');
	});

	$('#form').submit(function(event) {
		event.preventDefault();
		var $form = $(this);
		var $submitButton = $form.find('[type=submit]');

		$submitButton.attr('disabled', true);
		$submitButton.val('少々お待ちください...');

		$.ajax('https://api.misskey.xyz/account/create', {
			type: 'post',
			data: $form.serialize(),
			dataType: 'json',
			xhrFields: { withCredentials: true }
		}).done(function(data) {
			location.href = 'https://misskey.xyz';
		}).fail(function(data) {
			$submitButton.attr('disabled', false);
			$submitButton.text('失敗しました :(');
		});
	});
});

function initRegisterForm() {
	var userNameInputQuery = '#registerForm .user-name .user-name-input';

	initUserNameSection();

	function initUserNameSection() {
		var $nextButton = $('#registerForm .user-name button.next')

		$nextButton.click(function() {
			$('#registerForm .user-name').animate({
				left: '-50%',
				opacity: 0.2
			}, 500, 'easeOutQuint');
			$('#registerForm .nickname').animate({
				left: 0,
				opacity: 1
			}, 500, 'easeOutElastic');
		});

		$(userNameInputQuery).keyup(function() {
			$nextButton.attr('disabled', true);
			hideMessage();
			var sn = $(userNameInputQuery).val();

			if (sn == '') {
				return false;
			}
			if (sn.length < 4) {
				showMessage('4文字以上でお願いしますっ', false)
				return false;
			}
			if (sn.match(/^[0-9]+$/)) {
				showMessage('すべてを数字にすることはできませんっ', false)
				return false;
			}
			if (!sn.match(/^[a-zA-Z0-9_]+$/)) {
				showMessage('半角英数記号(_)のみでお願いしますっ', false)
				return false;
			}
			if (sn.length > 20) {
				showMessage('20文字以内でお願いします', false)
				return false;
			}

			showMessage('確認中...', null);
			$.ajax('https://api.misskey.xyz/screenname-available', {
				type: 'get',
				data: { 'screen-name': sn },
				dataType: 'json',
				xhrFields: { withCredentials: true }
			}).done(function(result) {
				if (result) {
					showMessage('このIDは既に使用されていますっ', false)
				} else {
					showMessage('このIDは使用できますっ！', true)
					$nextButton.attr('disabled', false);
				}
			}).fail(function() {
			});
		});

		function showMessage(message, success) {
			hideMessage();
			var klass = success == null ? '' : success ? 'done' : 'fail';
			var $message = $('
' + message + '
');
			$message.css('top', $(userNameInputQuery).position().top - $(userNameInputQuery).outerHeight() + ($message.outerHeight() / 2));
			$message.appendTo('#registerForm .user-name').animate({
				'margin-right': 0,
				opacity: 1
			}, 500, 'easeOutCubic');
		}

		function hideMessage() {
			$('#userNameAvailable').remove();
		}
	}
}

function showRegisterForm() {
	$('#registerForm').css({
		display: 'block'
	});
	$('#registerForm .user-name').animate({
		left: 0,
		opacity: 1
	}, 500, 'easeOutQuint');
}<commit_msg>Fix desfin<commit_after>$(function() {
	$("#loginForm").submit(function(event) {
		event.preventDefault();
		var $form = $(this);
		var $submitButton = $form.find("[type=submit]");

		$submitButton.attr("disabled", true);
		$form.css({
			"transform": "perspective(512px) rotateX(-90deg)",
			"opacity": "0",
			"transition": "all ease-in 0.5s"
		});

		$.ajax({
			url: $form.attr("action"),
			type: $form.attr("method"),
			data: $form.serialize()
		}).done(function() {
			location.reload();
		}).fail(function() {
			$submitButton.attr("disabled", false);
			setTimeout(function() {
				$form.css({
					"transform": "perspective(512px) scale(1)",
					"opacity": "1",
					"transition": "all ease 0.7s"
				});
			}, 500);
		});
	});

	$('#new').click(function() {
		showRegisterForm();
	});

	initRegisterForm();

	$('#name').keyup(function() {
		$("#nameAvailable").remove();
		var name = $('#name').val();
		if (name.length == 0) {
			return false;
		}
		$('#name').before('
Great!
');
	});

	$('#password').keyup(function() {
		$("#passwordAvailable").remove();
		var password = $('#password').val();
		if (password.length == 0) {
			return false;
		}
		if (password.length < 8) {
			$('#password').before('
8文字以上でお願いします
');
			return false;
		}
		$('#password').before('
Nice!
');
	});

	$('#passwordRetype').keyup(function() {
		$("#passwordRetypeAvailable").remove();
		var password = $('#password').val();
		var passwordRetype = $('#passwordRetype').val();
		if (passwordRetype.length == 0) {
			return false;
		}
		if (passwordRetype != password) {
			$('#passwordRetype').before('
一致していませんっ
');
			return false;
		}
		$('#passwordRetype').before('
Okay!
');
	});

	$('#color').change(function() {
		$("#colorAvailable").remove();
		var color = $('#color').val();
		$('#color').before('
Good!
');
	});

	$('#form').submit(function(event) {
		event.preventDefault();
		var $form = $(this);
		var $submitButton = $form.find('[type=submit]');

		$submitButton.attr('disabled', true);
		$submitButton.val('少々お待ちください...');

		$.ajax('https://api.misskey.xyz/account/create', {
			type: 'post',
			data: $form.serialize(),
			dataType: 'json',
			xhrFields: { withCredentials: true }
		}).done(function(data) {
			location.href = 'https://misskey.xyz';
		}).fail(function(data) {
			$submitButton.attr('disabled', false);
			$submitButton.text('失敗しました :(');
		});
	});
});

function initRegisterForm() {
	var userNameInputQuery = '#registerForm .user-name .user-name-input';

	initUserNameSection();

	function initUserNameSection() {
		var $nextButton = $('#registerForm .user-name button.next')

		$nextButton.click(function() {
			$('#registerForm .user-name').animate({
				left: '-50%',
				opacity: 0.2
			}, 500, 'easeOutQuint');
			$('#registerForm .nickname').animate({
				left: 0,
				opacity: 1
			}, 500, 'easeOutElastic');
		});

		$(userNameInputQuery).keyup(function() {
			$nextButton.attr('disabled', true);
			hideMessage();
			var sn = $(userNameInputQuery).val();

			if (sn == '') {
				return false;
			}
			if (sn.length < 4) {
				showMessage('4文字以上でお願いしますっ', false)
				return false;
			}
			if (sn.match(/^[0-9]+$/)) {
				showMessage('すべてを数字にすることはできませんっ', false)
				return false;
			}
			if (!sn.match(/^[a-zA-Z0-9_]+$/)) {
				showMessage('半角英数記号(_)のみでお願いしますっ', false)
				return false;
			}
			if (sn.length > 20) {
				showMessage('20文字以内でお願いします', false)
				return false;
			}

			showMessage('確認中...', null);
			$.ajax('https://api.misskey.xyz/screenname-available', {
				type: 'get',
				data: { 'screen-name': sn },
				dataType: 'json',
				xhrFields: { withCredentials: true }
			}).done(function(result) {
				if (result) {
					showMessage('このIDは既に使用されていますっ', false)
				} else {
					showMessage('このIDは使用できますっ！', true)
					$nextButton.attr('disabled', false);
				}
			}).fail(function() {
			});
		});

		function showMessage(message, success) {
			hideMessage();
			var klass = success == null ? '' : success ? 'done' : 'fail';
			var $message = $('
' + message + '
');
			$message.css('top', $(userNameInputQuery).position().top + ($(userNameInputQuery).outerHeight() / 2) - ($message.outerHeight() / 2));
			$message.appendTo('#registerForm .user-name').animate({
				'margin-right': 0,
				opacity: 1
			}, 500, 'easeOutCubic');
		}

		function hideMessage() {
			$('#userNameAvailable').remove();
		}
	}
}

function showRegisterForm() {
	$('#registerForm').css({
		display: 'block'
	});
	$('#registerForm .user-name').animate({
		left: 0,
		opacity: 1
	}, 500, 'easeOutQuint');
}<|endoftext|>


<commit_before>var MessageOut = new Class({
	id: 0,
	data: null,
	dataView: null,
	length: 0,
	maxLength: 1000,

	//Konstruktor
	initialize: function(id)
	{
        this.id=id;

		this.data=new ArrayBuffer(this.maxLength);
		this.dataView=new DataView(this.data);

		//ID schreiben
		this.addValueAsInt16(this.id);
    },

	//Methoden
    addValueAsInt8: function(value)
	{
		if((this.length+1)>=this.maxLength)
		{
			log.error('Maximum byte count for MessageOut is reached.');
			return;
		}

		this.dataView.setInt8(this.length, value, true);
		this.length+=1;
    },

    addValueAsInt16: function(value)
	{
		if((this.length+2)>=this.maxLength)
		{
			log.error('Maximum byte count for MessageOut is reached.');
			return;
		}

		this.dataView.setInt16(this.length, value, true);
		this.length+=2;
    },

    addValueAsInt32: function(value)
	{
		if((this.length+4)>=this.maxLength)
		{
			log.error('Maximum byte count for MessageOut is reached.');
			return;
		}

		this.dataView.setInt32(this.length, value, true);
		this.length+=4;
    },

    addValueAsString: function(value)
	{
		if((this.length+2)>=this.maxLength)
		{
			log.error('Maximum byte count for MessageOut is reached.');
			return;
		}

		//String umwandeln
		var tmp=Utf8Utils.encode(value);

		//Länge setzen (in Zeichen)
		this.addValueAsInt16(tmp.length, true);

		//In Arraybuffer schreiben
		var b = new Uint8Array(this.data);
		for(var i = 0; i < tmp.length; i++){
		    b[this.length+i] = tmp[i];
		}

		//Länge aktualisieren
		this.length+=tmp.length;
    },

	send: function(socket)
	{
		log.warn(sprintf("Send message: %s", getEnumFromInteger(Protocol, this.id)));
		socket.send(this.getBinary());
	},

	getBinary: function()
	{
		//Gibt das Datenarray zurück und schneidet es vorher auf die richtige Größe
		return this.data.slice(0, this.length);
	}
});<commit_msg>warn durch debug in der Message ersetzt.<commit_after>var MessageOut = new Class({
	id: 0,
	data: null,
	dataView: null,
	length: 0,
	maxLength: 1000,

	//Konstruktor
	initialize: function(id)
	{
        this.id=id;

		this.data=new ArrayBuffer(this.maxLength);
		this.dataView=new DataView(this.data);

		//ID schreiben
		this.addValueAsInt16(this.id);
    },

	//Methoden
    addValueAsInt8: function(value)
	{
		if((this.length+1)>=this.maxLength)
		{
			log.error('Maximum byte count for MessageOut is reached.');
			return;
		}

		this.dataView.setInt8(this.length, value, true);
		this.length+=1;
    },

    addValueAsInt16: function(value)
	{
		if((this.length+2)>=this.maxLength)
		{
			log.error('Maximum byte count for MessageOut is reached.');
			return;
		}

		this.dataView.setInt16(this.length, value, true);
		this.length+=2;
    },

    addValueAsInt32: function(value)
	{
		if((this.length+4)>=this.maxLength)
		{
			log.error('Maximum byte count for MessageOut is reached.');
			return;
		}

		this.dataView.setInt32(this.length, value, true);
		this.length+=4;
    },

    addValueAsString: function(value)
	{
		if((this.length+2)>=this.maxLength)
		{
			log.error('Maximum byte count for MessageOut is reached.');
			return;
		}

		//String umwandeln
		var tmp=Utf8Utils.encode(value);

		//Länge setzen (in Zeichen)
		this.addValueAsInt16(tmp.length, true);

		//In Arraybuffer schreiben
		var b = new Uint8Array(this.data);
		for(var i = 0; i < tmp.length; i++){
		    b[this.length+i] = tmp[i];
		}

		//Länge aktualisieren
		this.length+=tmp.length;
    },

	send: function(socket)
	{
		log.debug(sprintf("Send message: %s", getEnumFromInteger(Protocol, this.id)));
		socket.send(this.getBinary());
	},

	getBinary: function()
	{
		//Gibt das Datenarray zurück und schneidet es vorher auf die richtige Größe
		return this.data.slice(0, this.length);
	}
});<|endoftext|>


<commit_before>angular.module('anol.layerswitcher', [])

.directive('anolLayerswitcher', ['LayersService', function(LayersService) {
    return {
        restrict: 'A',
        transclude: true,
        templateUrl: 'anol/modules/layerswitcher/templates/layerswitcher.html',
        scope: {},
        link: function(scope, element, attrs) {
            scope.backgroundLayers = LayersService.backgroundLayers;
            angular.forEach(scope.backgroundLayers, function(layer) {
                if(layer.getVisible() === true) {
                    if(scope.backgroundLayer !== undefined) {
                        scope.backgroundLayer.setVisible(false);
                    }
                    scope.backgroundLayer = layer;
                }
            });
            scope.overlayLayers = LayersService.overlayLayers;
            scope.$watch('backgroundLayer', function(newVal, oldVal) {
                oldVal.setVisible(false);
                newVal.setVisible(true);
            });
        }
    };
}]);
<commit_msg>Fixed initial background layer. Use always first visible.<commit_after>angular.module('anol.layerswitcher', [])

.directive('anolLayerswitcher', ['LayersService', function(LayersService) {
    return {
        restrict: 'A',
        transclude: true,
        templateUrl: 'anol/modules/layerswitcher/templates/layerswitcher.html',
        scope: {},
        link: function(scope, element, attrs) {
            scope.$watch('backgroundLayer', function(newVal, oldVal) {
                oldVal.setVisible(false);
                newVal.setVisible(true);
            });
        },
        controller: function($scope, $element, $attrs) {
            $scope.backgroundLayers = LayersService.backgroundLayers;
            angular.forEach($scope.backgroundLayers, function(layer) {
                if(layer.getVisible() === true) {
                    if($scope.backgroundLayer !== undefined) {
                        $scope.backgroundLayer.setVisible(false);
                    }
                    $scope.backgroundLayer = layer;
                }
            });
            $scope.overlayLayers = LayersService.overlayLayers;
        }
    };
}]);
<|endoftext|>


<commit_before>const onDOMReady = function() {
  //
  // Use ActiveAdmin.modal_dialog to prompt user if
  // confirmation is required for current Batch Action
  //
  $('.batch_actions_selector li a').click(function(event){
    let message;
    event.stopPropagation(); // prevent Rails UJS click event
    event.preventDefault();
    if ((message = $(this).data('confirm'))) {
      ActiveAdmin.modal_dialog(message, $(this).data('inputs'), inputs => {
        $(this).trigger('confirm:complete', inputs);
      });
    } else {
      $(this).trigger('confirm:complete');
    }
  });

  $('.batch_actions_selector li a').on('confirm:complete', function(event, inputs){
    let val;
    if ((val = JSON.stringify(inputs))) {
      $('#batch_action_inputs').removeAttr('disabled').val(val);
    } else {
      $('#batch_action_inputs').attr('disabled', 'disabled');
    }

    $('#batch_action').val($(this).data('action'));
    $('#collection_selection').submit();
  });

  //
  // Add checkbox selection to resource tables and lists if batch actions are enabled
  //

  if ($(".batch_actions_selector").length && $(":checkbox.toggle_all").length) {

    if ($(".paginated_collection table.index_table").length) {
      $(".paginated_collection table.index_table").tableCheckboxToggler();
    } else {
      $(".paginated_collection").checkboxToggler();
    }

    $(document).on('change', '.paginated_collection :checkbox', function() {
      if ($(".paginated_collection :checkbox:checked").length && $(".dropdown_menu_list").children().length) {
        $(".batch_actions_selector").each(function() { $(this).aaDropdownMenu("enable"); });
      } else {
        $(".batch_actions_selector").each(function() { $(this).aaDropdownMenu("disable"); });
      }
    });
  }
};

$(document).
  ready(onDOMReady).
  on('page:load turbolinks:load', onDOMReady);
<commit_msg>Detach previous batch_action click handler before attaching new one<commit_after>const onDOMReady = function() {
  //
  // Use ActiveAdmin.modal_dialog to prompt user if
  // confirmation is required for current Batch Action
  //
  $('.batch_actions_selector li a').off('click').on('click', function(event){
    let message;
    event.stopPropagation(); // prevent Rails UJS click event
    event.preventDefault();
    if ((message = $(this).data('confirm'))) {
      ActiveAdmin.modal_dialog(message, $(this).data('inputs'), inputs => {
        $(this).trigger('confirm:complete', inputs);
      });
    } else {
      $(this).trigger('confirm:complete');
    }
  });

  $('.batch_actions_selector li a').on('confirm:complete', function(event, inputs){
    let val;
    if ((val = JSON.stringify(inputs))) {
      $('#batch_action_inputs').removeAttr('disabled').val(val);
    } else {
      $('#batch_action_inputs').attr('disabled', 'disabled');
    }

    $('#batch_action').val($(this).data('action'));
    $('#collection_selection').submit();
  });

  //
  // Add checkbox selection to resource tables and lists if batch actions are enabled
  //

  if ($(".batch_actions_selector").length && $(":checkbox.toggle_all").length) {

    if ($(".paginated_collection table.index_table").length) {
      $(".paginated_collection table.index_table").tableCheckboxToggler();
    } else {
      $(".paginated_collection").checkboxToggler();
    }

    $(document).on('change', '.paginated_collection :checkbox', function() {
      if ($(".paginated_collection :checkbox:checked").length && $(".dropdown_menu_list").children().length) {
        $(".batch_actions_selector").each(function() { $(this).aaDropdownMenu("enable"); });
      } else {
        $(".batch_actions_selector").each(function() { $(this).aaDropdownMenu("disable"); });
      }
    });
  }
};

$(document).
  ready(onDOMReady).
  on('page:load turbolinks:load', onDOMReady);
<|endoftext|>