<commit_before>/*
This file is part of SOS Pomoc application.

SOS Pomoc application is free software: you can redistribute it and/or
modify it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

SOS Pomoc application is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public
License along with SOS Pomoc application.  If not, see
<http://www.gnu.org/licenses/>.
*/

'use strict';

angular.module('sosPomocApp')
  .controller('AdFormCtrl', function ($scope, Ad, adsService, $http, $routeParams, $location) {

    $scope.findMe = function() {
      if ($scope.geolocationAvailable) {
        return navigator.geolocation.getCurrentPosition(function(position) {
          return $scope.$apply(function() {
            return $scope.newItem.location = {
              lat: position.coords.latitude,
              lon: position.coords.longitude
            };
          });
        }, function() {});
      }
    };

    $scope.initAutocomplete = function() {
      var autocomplete, input;
      input = document.getElementById('newLocation');
      if(input)  {
          autocomplete = new google.maps.places.Autocomplete(input);
          google.maps.event.addDomListener(input, 'keydown', function(e) {
            if (e.keyCode === 13) {
              return e.preventDefault();
            }
          });

          return google.maps.event.addListener(autocomplete, 'place_changed', function() {
            var place;
            place = autocomplete.getPlace();
            if (!place.geometry) {
              return;
            }
            if (place.geometry.location) {
              return $scope.$apply(function() {
                return $scope.newItem.location = {
                  lat: place.geometry.location.jb,
                  lon: place.geometry.location.kb,
                  name: document.getElementById('newLocation').value
                };
              });
            }
          });
      }
    };

    var loadAd = function(id) {
        Ad.get({'id':id}, (function(data) {
            if(data.errors) {
                $location.path('/')
            } else {
                angular.forEach(data.categories, function(v, k) {
                data.categories[k].checked = true
                })
                $scope.newItem = data
                $scope.newItem.categories = $.extend($scope.allCategories, $scope.newItem.categories)
                $scope.newItem.location.name = $scope.newItem.location.place
                delete $scope.newItem.location.place
            }
        }))
    }

    $scope.remove = function() {
        Ad.remove({'id': $routeParams.id}, function(data) {
            if(data.ok) {
                $location.path('/')
            } else {
                $scope.errors.push('Smazání se nezdařilo')
            }
        })
    }

    $scope.init = function() {
      $scope.errors = []
      $scope.formSent = false
      $scope.newItem = {}
      $scope.asked = false
      $scope.isTouchDevice = $('html').hasClass('touch')
      $scope.geolocationAvailable = false //default
      $scope.editMode = false
      $scope.allCategories = adsService.categories().map(function(category) {
        category.checked = false;
        return category;
      });
      if($routeParams.id) {
          loadAd($routeParams.id)
          $scope.editMode = true
      } else {
          $scope.newItem.categories = angular.copy($scope.allCategories);
          if(!$scope.newItem.location && $scope.isTouchDevice) {
              $scope.geolocationAvailable = navigator.geolocation ? true : false
              $scope.asked = true
              $scope.findMe()
          }
      }
      $scope.initAutocomplete();
    }

    var createAd = function() {
        var categoriesBackup = angular.copy($scope.newItem.categories)
        $scope.newItem.categories = $scope.newItem.categories.filter(function (el, idx, arr) { return el.checked == true; })
        if($scope.editMode) {
            $scope.newItem.token = $routeParams.id
            Ad.edit({'id': $routeParams.id}, $scope.newItem, function(data) {
                $scope.newItem.categories = categoriesBackup
                if(data.errors) {
                    $scope.errors.push("Odeslání se nezdařilo")
                }
                else {
                    $scope.errors = [];
                    $scope.formSent = true;
                }
            })
        } else {
            Ad.create($scope.newItem, (function(data){
                if(data.errors) {
                    $scope.errors.push("Odeslání se nezdařilo")
                    $scope.newItem.categories = categoriesBackup
                }
                else {
                    $scope.errors = [];
                    $scope.formSent = true;
                    $scope.newItem = {}
                    $scope.newItem.categories = $scope.allCategories
                }
            }))
        }
    }

    $scope.submit = function() {
      $scope.errors = []
      $scope.formSent = false
      if(!$scope.createForm.$invalid) {
        if(!$scope.newItem.location) {
          $scope.errors.push("Lokalita je povinná položka.");
        }
        else {
          if($scope.newItem.location.name) {
              $scope.newItem.location.place = $scope.newItem.location.name
              createAd()
          }
          else {
              var location = $scope.newItem.location
              var url = 'http://maps.googleapis.com/maps/api/geocode/json?latlng='+ location.lat + ',' + location.lon + '&sensor=true'
              $http.get(url).success(function(data) {
                  if(data.results.length > 0)   $scope.newItem.location.place = data.results[0].formatted_address
                  createAd()
              })
          }
        }
      }
    }

    $scope.toggleCategory = function(category) {
      //$scope.newItem.categories[index].checked = !$scope.newItem.categories[index].checked
      category.checked = !category.checked;
    }

  });
<commit_msg>added validation for categories<commit_after>/*
This file is part of SOS Pomoc application.

SOS Pomoc application is free software: you can redistribute it and/or
modify it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

SOS Pomoc application is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public
License along with SOS Pomoc application.  If not, see
<http://www.gnu.org/licenses/>.
*/

'use strict';

angular.module('sosPomocApp')
  .controller('AdFormCtrl', function ($scope, Ad, adsService, $http, $routeParams, $location) {

    $scope.findMe = function() {
      if ($scope.geolocationAvailable) {
        return navigator.geolocation.getCurrentPosition(function(position) {
          return $scope.$apply(function() {
            return $scope.newItem.location = {
              lat: position.coords.latitude,
              lon: position.coords.longitude
            };
          });
        }, function() {});
      }
    };

    $scope.initAutocomplete = function() {
      var autocomplete, input;
      input = document.getElementById('newLocation');
      if(input)  {
          autocomplete = new google.maps.places.Autocomplete(input);
          google.maps.event.addDomListener(input, 'keydown', function(e) {
            if (e.keyCode === 13) {
              return e.preventDefault();
            }
          });

          return google.maps.event.addListener(autocomplete, 'place_changed', function() {
            var place;
            place = autocomplete.getPlace();
            if (!place.geometry) {
              return;
            }
            if (place.geometry.location) {
              return $scope.$apply(function() {
                return $scope.newItem.location = {
                  lat: place.geometry.location.jb,
                  lon: place.geometry.location.kb,
                  name: document.getElementById('newLocation').value
                };
              });
            }
          });
      }
    };

    var loadAd = function(id) {
        Ad.get({'id':id}, (function(data) {
            if(data.errors) {
                $location.path('/')
            } else {
                angular.forEach(data.categories, function(v, k) {
                data.categories[k].checked = true
                })
                $scope.newItem = data
                $scope.newItem.categories = $.extend($scope.allCategories, $scope.newItem.categories)
                $scope.newItem.location.name = $scope.newItem.location.place
                delete $scope.newItem.location.place
            }
        }))
    }

    $scope.remove = function() {
        Ad.remove({'id': $routeParams.id}, function(data) {
            if(data.ok) {
                $location.path('/')
            } else {
                $scope.errors.push('Smazání se nezdařilo')
            }
        })
    }

    $scope.init = function() {
      $scope.errors = []
      $scope.formSent = false
      $scope.newItem = {}
      $scope.asked = false
      $scope.isTouchDevice = $('html').hasClass('touch')
      $scope.geolocationAvailable = false //default
      $scope.editMode = false
      $scope.allCategories = adsService.categories().map(function(category) {
        category.checked = false;
        return category;
      });
      if($routeParams.id) {
          loadAd($routeParams.id)
          $scope.editMode = true
      } else {
          $scope.newItem.categories = angular.copy($scope.allCategories);
          if(!$scope.newItem.location && $scope.isTouchDevice) {
              $scope.geolocationAvailable = navigator.geolocation ? true : false
              $scope.asked = true
              $scope.findMe()
          }
      }
      $scope.initAutocomplete();
    }

    var createAd = function(categoriesBackup) {
        if($scope.editMode) {
            $scope.newItem.token = $routeParams.id
            Ad.edit({'id': $routeParams.id}, $scope.newItem, function(data) {
                $scope.newItem.categories = categoriesBackup
                if(data.errors) {
                    $scope.errors.push("Odeslání se nezdařilo")
                }
                else {
                    $scope.errors = [];
                    $scope.formSent = true;
                }
            })
        } else {
            Ad.create($scope.newItem, (function(data){
                if(data.errors) {
                    $scope.errors.push("Odeslání se nezdařilo")
                    $scope.newItem.categories = categoriesBackup
                }
                else {
                    $scope.errors = [];
                    $scope.formSent = true;
                    $scope.newItem = {}
                    $scope.newItem.categories = $scope.allCategories
                }
            }))
        }
    }

    var filterCategories = function() {
        return $scope.newItem.categories.filter(function (el, idx, arr) { return el.checked == true; })
    }

    var validate = function() {
        $scope.errors = []
        var filtered = filterCategories()
        if(!filtered.length) {
          $scope.errors.push("Vyberte alespoň jednu kategorii.")
        }
        if(!$scope.newItem.location) {
          $scope.errors.push("Lokalita je povinná položka.")
        }
    }

    $scope.submit = function() {
      $scope.formSent = false
      if(!$scope.createForm.$invalid) {
        validate()
        if(!$scope.errors.length) {
          var categoriesBackup = angular.copy($scope.newItem.categories)
          $scope.newItem.categories = filterCategories()
          if($scope.newItem.location.name) {
              $scope.newItem.location.place = $scope.newItem.location.name
              createAd(categoriesBackup)
          }
          else {
              var location = $scope.newItem.location
              var url = 'http://maps.googleapis.com/maps/api/geocode/json?latlng='+ location.lat + ',' + location.lon + '&sensor=true'
              $http.get(url).success(function(data) {
                  if(data.results.length > 0)   $scope.newItem.location.place = data.results[0].formatted_address
                  createAd(categoriesBackup)
              })
          }
        }
      }
    }

    $scope.toggleCategory = function(category) {
      category.checked = !category.checked;
    }

  });
<|endoftext|>


<commit_before>/**
 *  Entry point for dashboard
 */

$(function() {

  var Dashboard = cdb.core.View.extend({

    el: document.body,

    events: {},

    initialize: function() {
      _.bindAll(this, "_whenScroll");

      this._initModels();
      this._initViews();

      // Move aside when scrolls
      $(window).scroll(this._whenScroll);
    },

    _initModels: function() {
      this.user = new cdb.admin.User(this.options.user_data);
      this.tables = new cdb.admin.Tables();
      this.tags = new cdb.admin.Tags();
      this.first_time = true;

      // The user model has to update every time the table model
      this.tables.bind('add remove reset', function(){
        if (!this.first_time)
          this.user.fetch();

        this.first_time = false;
      }, this);
      this.tables.bind('error', function(e) {
        cdb.log.info("error", e);
      });
    },

    _initViews: function() {
      // Table list
      this.tableList = new cdb.admin.dashboard.TableList({
        el: this.$('#tablelist'),
        model: this.tables,
        config: this.options.config,
        user: this.user
      });

      // User data
      this.user_stats = new cdb.admin.dashboard.UserStats({
        el: this.$('div.subheader'),
        model: this.user
      });

      this.user_stats.render();

      // Choose sceneario
      this.scenario = new cdb.admin.dashboard.Scenario({
        el: this.$el,
        model: this.user
      });

      // Search form
      var search_form = this.search_form = new cdb.ui.common.SearchView({
        el: this.$('header ul li.search')
      });

      // User menu
      var user_menu = this.user_menu = new cdb.admin.DropdownMenu({
        target:         $('a.account'),
        host:           config.account_host,
        username:       username,
        template_base:  'common/views/settings_item'
      });
      cdb.god.bind("closeDialogs", user_menu.hide, user_menu);
      this.$el.append(this.user_menu.render().el);

      // Background Importer
      var bkg_importer = this.bkg_importer = new cdb.ui.common.BackgroundImporter({
        template_base: 'common/views/background_importer'
      });
      this.$el.append(this.bkg_importer.render().el);

      // Paginator
      var paginator = this.paginator = new cdb.admin.dashboard.DashboardPaginator({
        el: this.$("div.paginator"),
        model: this.tables
      });

      // Tables tags
      var tagsView = this.tagsView = new cdb.admin.dashboard.TagsView({
        el: this.$('aside div.content ul:eq(0)'),
        tables: this.tables,
        model: this.tags
      });

      // Tipsy
      this.$el.find("a.tooltip").tipsy({gravity: 's', fade:true, live:true});

      // Create new table view
      var createTable = this.createTable = new cdb.admin.dashboard.CreateTable({
        el:       this.$el,
        importer: this.bkg_importer,
        tables:   this.tables,
        model:    this.user
      });

      // global click
      enableClickOut(this.$el);
    },

    /**
     *  Calculate scroll pagination and moves the aside
     *  when it is necessary
     */
    _whenScroll: function(ev) {
      var $aside      = this.$el.find('aside')
        , $list       = this.$el.find('section.tables')
        , $warning    = this.$el.find("section.warning")
        , scrolled    = $(ev.target).scrollTop()
        , aside_h     = $aside.outerHeight()
        , list_pos    = $list.offset().top
        , list_height = $list.outerHeight();

      if ( scrolled > list_pos ) {
        if ((scrolled + aside_h) < (list_pos + list_height)) {
          $aside
            .addClass("moving")
            .css({
              marginTop: - list_pos - ($warning.hasClass("visible") ? $warning.outerHeight() : 0)
            })
            .removeClass("bottom");
        } else {
          $aside
            .addClass("bottom")
            .removeClass("moving")
            .css({
              marginTop: list_height - aside_h
            })
        }
      } else {
        $aside
          .removeClass("moving bottom")
          .css({
            marginTop: 0
          })
      }
    },

    /**
     *  If application suffers any update in the Router
     *  moves the window at the top to see the loader
     */
    scrollTop: function() {
      this.$el.animate({
        scrollTop: 0
      },500);
    }

  });

  var DashboardRouter = Backbone.Router.extend({

    routes: {
      '':                 'index',
      'page/:p':          'paginate',
      'tag/:tag/:p':      'searchTag',
      'search/:query/:p': 'searchQuery'
    },

    initialize: function() {
      window.dashboard.tables.options.bind("change", this.update ,this);
    },

    update: function() {
      window.dashboard.scrollTop();
      var hash = window.location.hash.split("/");
      hash[hash.length - 1] = window.dashboard.tables.options.get("page");
      this.navigate(hash.join("/"));
    },

    index: function() {
      window.dashboard.tables.options.set({
        "tag_name"  : "",
        "q"         : "",
        "page"      : 1
      });
    },
    searchTag: function(tag,p) {
      window.dashboard.tables.options.set({
        "tag_name"  : tag,
        "page"      : p,
        "q"         : ""
      });
    },
    searchQuery: function(query,p) {
      window.dashboard.tables.options.set({
        "tag_name"  : "",
        "page"      : p,
        "q"         : query
      });
    },
    paginate: function(p) {
      window.dashboard.tables.options.set({
        "tag_name"  : "",
        "page"      : p,
        "q"         : ""
      });
    }
  });

  cdb.init(function() {
    cdb.templates.namespace = 'cartodb/';
    var dashboard = new Dashboard({
      user_data: user_data,
      config: config
    });

    // Expose to debug
    window.dashboard = dashboard;

    // Routing
    var router = new DashboardRouter();
    Backbone.history.start();

    // No route => tables fetch
    if (window.dashboard.tables.options.get("tag_name") === "" &&
      window.dashboard.tables.options.get("q") === "") {
      window.dashboard.tables.fetch();
    }
  });

});
<commit_msg>tables cleared before you change the page<commit_after>/**
 *  Entry point for dashboard
 */

$(function() {

  var Dashboard = cdb.core.View.extend({

    el: document.body,

    events: {
      'click .paginator a': 'pageChange'
    },

    initialize: function() {
      _.bindAll(this, 'pageChange')
      this._initModels();
      this._initViews();

    },

    _initModels: function() {
      this.user = new cdb.admin.User(this.options.user_data);
      this.tables = new cdb.admin.Tables();
      this.tags = new cdb.admin.Tags();
      this.first_time = true;

      // The user model has to update every time the table model
      this.tables.bind('add remove reset', function(){
        if (!this.first_time)
          this.user.fetch();

        this.first_time = false;
      }, this);
      this.tables.bind('error', function(e) {
        cdb.log.info("error", e);
      });
    },

    _initViews: function() {
      // Table list
      this.tableList = new cdb.admin.dashboard.TableList({
        el: this.$('#tablelist'),
        model: this.tables,
        config: this.options.config,
        user: this.user
      });

      // User data
      this.user_stats = new cdb.admin.dashboard.UserStats({
        el: this.$('div.subheader'),
        model: this.user
      });

      this.user_stats.render();

      // Choose sceneario
      this.scenario = new cdb.admin.dashboard.Scenario({
        el: this.$el,
        model: this.user
      });

      // Search form
      var search_form = this.search_form = new cdb.ui.common.SearchView({
        el: this.$('header ul li.search')
      });

      // User menu
      var user_menu = this.user_menu = new cdb.admin.DropdownMenu({
        target:         $('a.account'),
        host:           config.account_host,
        username:       username,
        template_base:  'common/views/settings_item'
      });
      cdb.god.bind("closeDialogs", user_menu.hide, user_menu);
      this.$el.append(this.user_menu.render().el);

      // Background Importer
      var bkg_importer = this.bkg_importer = new cdb.ui.common.BackgroundImporter({
        template_base: 'common/views/background_importer'
      });
      this.$el.append(this.bkg_importer.render().el);

      // Paginator
      var paginator = this.paginator = new cdb.admin.dashboard.DashboardPaginator({
        el: this.$("div.paginator"),
        model: this.tables
      });

      // Tables tags
      var tagsView = this.tagsView = new cdb.admin.dashboard.TagsView({
        el: this.$('aside div.content ul:eq(0)'),
        tables: this.tables,
        model: this.tags
      });

      // Tipsy
      this.$el.find("a.tooltip").tipsy({gravity: 's', fade:true, live:true});

      // Create new table view
      var createTable = this.createTable = new cdb.admin.dashboard.CreateTable({
        el:       this.$el,
        importer: this.bkg_importer,
        tables:   this.tables,
        model:    this.user
      });

      // global click
      enableClickOut(this.$el);
    },

    pageChange: function(ev) {
      if($(ev.currentTarget).attr('href') != location.hash) {
        this.$('.content ul').html('

');
      }
    },

  });

  var DashboardRouter = Backbone.Router.extend({

    routes: {
      '':                 'index',
      'page/:p':          'paginate',
      'tag/:tag/:p':      'searchTag',
      'search/:query/:p': 'searchQuery'
    },

    initialize: function() {
      window.dashboard.tables.options.bind("change", this.update ,this);
    },

    update: function() {
      var hash = window.location.hash.split("/");
      hash[hash.length - 1] = window.dashboard.tables.options.get("page");
      this.navigate(hash.join("/"));
    },

    index: function() {
      window.dashboard.tables.options.set({
        "tag_name"  : "",
        "q"         : "",
        "page"      : 1
      });
    },
    searchTag: function(tag,p) {
      window.dashboard.tables.options.set({
        "tag_name"  : tag,
        "page"      : p,
        "q"         : ""
      });
    },
    searchQuery: function(query,p) {
      window.dashboard.tables.options.set({
        "tag_name"  : "",
        "page"      : p,
        "q"         : query
      });
    },
    paginate: function(p) {
      window.dashboard.tables.options.set({
        "tag_name"  : "",
        "page"      : p,
        "q"         : ""
      });
    }
  });

  cdb.init(function() {
    cdb.templates.namespace = 'cartodb/';
    var dashboard = new Dashboard({
      user_data: user_data,
      config: config
    });

    // Expose to debug
    window.dashboard = dashboard;

    // Routing
    var router = new DashboardRouter();
    Backbone.history.start();

    // No route => tables fetch
    if (window.dashboard.tables.options.get("tag_name") === "" &&
      window.dashboard.tables.options.get("q") === "") {
      window.dashboard.tables.fetch();
    }
  });

});
<|endoftext|>


<commit_before>import { ToggleTool/*, FontAwesomeIcon*/ } from 'substance'

export default class FunctionUsageTool extends ToggleTool {
  render($$) {
    let messages = this.props.commandState.messages
    let el = $$('div').addClass('sc-code-errors-tool')

    let errorsEl = $$('div').addClass('se-errors')
    if (messages.length > 0) {
      messages.forEach((err) => {
        errorsEl.append(
          $$('div').addClass('se-error').append(
            'Error: ',
            err.message
          )
        )
      })
    }
    el.append(errorsEl)
    return el
  }
}
<commit_msg>Remove obsolete code.<commit_after><|endoftext|>


<commit_before>import Widget from "./base_widget.js";
import { generate_route } from "./utils";

export default class OnboardingWidget extends Widget {
	constructor(opts) {
		super(opts);
	}

	make_body() {
		this.body.addClass("grid");
		if (this.steps.length < 5) {
			this.body.addClass(`grid-rows-${this.steps.length}`);
		} else if (this.steps.length >= 5) {
			this.body.addClass("grid-rows-5");
		}
		this.steps.forEach((step) => {
			this.add_step(step);
		});
	}

	add_step(step) {
		// Make Step
		let status = "";
		let icon_class = "fa-circle-o";

		if (step.is_skipped) {
			status = "skipped";
			icon_class = "fa-check-circle-o";
		}

		if (step.is_complete) {
			status = "complete";
			icon_class = "fa-check-circle-o";
		}

		let $step = $(`

				${step.title}

`);

		step.$step = $step;

		// Add skip button
		if (!step.is_mandatory && !step.is_complete) {
			let skip_html = $(
				`<span class="ml-5 small text-muted step-skip">Skip</span>`
			);

			skip_html.appendTo($step);
			skip_html.on("click", () => {
				this.skip_step(step);
				event.stopPropagation();
			});
		}

		// Setup actions
		let actions = {
			"Watch Video": () => this.show_video(step),
			"Create Entry": () => {
				if (step.show_full_form) {
					this.create_entry(step);
				} else {
					this.show_quick_entry(step);
				}
			},
			"Show Form Tour": () => this.show_form_tour(step),
			"Update Settings": () => this.update_settings(step),
			"View Report": () => this.open_report(step),
			"Go to Page": () => this.go_to_page(step),
		};

		$step.find("#title").on("click", actions[step.action]);

		$step.appendTo(this.body);
		return $step;
	}

	go_to_page(step) {
		frappe.set_route(step.path).then(() => {
			if (step.callback_message) {
				let msg_dialog = frappe.msgprint({
					message: __(step.callback_message),
					title: __(step.callback_title),
					primary_action: {
						action: () => {
							msg_dialog.hide();
						},
						label: () => __("Continue"),
					},
					wide: true,
				});
			}
		});
	}

	open_report(step) {
		let route = generate_route({
			name: step.reference_report,
			type: "report",
			is_query_report: ["Query Report", "Script Report"].includes(
				step.report_type
			),
			doctype: step.report_reference_doctype,
		});

		let current_route = frappe.get_route();

		frappe.set_route(route).then(() => {
			let msg_dialog = frappe.msgprint({
				message: __(step.report_description),
				title: __(step.reference_report),
				primary_action: {
					action: () => {
						frappe.set_route(current_route).then(() => {
							this.mark_complete(step);
						});
						msg_dialog.hide();
					},
					label: () => __("Continue"),
				},
				secondary_action: {
					action: () => {
						msg_dialog.hide();
						frappe.set_route(current_route).then(() => {
							this.mark_complete(step);
						});
					},
					label: __("Go Back"),
				},
			});

			frappe.msg_dialog.custom_onhide = () => this.mark_complete(step);
		});
	}

	show_form_tour(step) {
		let route;
		if (step.is_single) {
			route = `Form/${step.reference_document}`;
		} else {
			route = `Form/${step.reference_document}/New ${step.reference_document}`;
		}

		let current_route = frappe.get_route();

		frappe.route_hooks = {};
		frappe.route_hooks.after_load = (frm) => {
			frm.show_tour(() => {
				let msg_dialog = frappe.msgprint({
					message: __("Let's take you back to onboarding"),
					title: __("Great Job"),
					primary_action: {
						action: () => {
							frappe.set_route(current_route).then(() => {
								this.mark_complete(step);
							});
							msg_dialog.hide();
						},
						label: () => __("Continue"),
					},
				});
			});
		};

		frappe.set_route(route);
	}

	update_settings(step) {
		let current_route = frappe.get_route();

		frappe.route_hooks = {};
		frappe.route_hooks.after_load = (frm) => {
			frm.scroll_to_field(step.field);
			frm.doc.__unsaved = true;
		};

		frappe.route_hooks.after_save = (frm) => {
			let success = false;
			let args = {};

			let value = frm.doc[step.field];
			let custom_onhide = null;

			if (value && step.value_to_validate == "%") success = true;
			if (value == step.value_to_validate) success = true;
			if (cstr(value) == cstr(step.value_to_validate)) success = true;

			if (success) {
				args.message = __("Let's take you back to onboarding");
				args.title = __("Looks Great");
				args.primary_action = {
					action: () => {
						frappe.set_route(current_route).then(() => {
							this.mark_complete(step);
						});
					},
					label: __("Continue"),
				};

				custom_onhide = () => args.primary_action.action();
			} else {
				args.message = __("Looks like you didn't change the value");
				args.title = __("Oops");
				args.secondary_action = {
					action: () => frappe.set_route(current_route),
					label: __("Go Back"),
				};

				if (!step.is_mandatory) {
					args.primary_action = {
						action: () => {
							frappe.set_route(current_route).then(() => {
								setTimeout(() => {
									this.skip_step(step);
								}, 300);
							});
						},
						label: __("Skip Step"),
					};
				}

				custom_onhide = () => args.secondary_action.action();
			}

			frappe.msgprint(args);
			frappe.msg_dialog.custom_onhide = () => custom_onhide();
		};

		frappe.set_route("Form", step.reference_document);
	}

	create_entry(step) {
		let current_route = frappe.get_route();

		frappe.route_hooks = {};
		let callback = () => {
			frappe.msgprint({
				message: __("You're doing great, let's take you back to the onboarding page."),
				title: __("Good Work 🎉"),
				primary_action: {
					action: () => {
						frappe.set_route(current_route).then(() => {
							this.mark_complete(step);
						});
					},
					label: __("Continue"),
				},
			});

			frappe.msg_dialog.custom_onhide = () => {
				this.mark_complete(step);
			};
		};

		if (step.is_submittable) {
			frappe.route_hooks.after_save = () => {
				frappe.msgprint({
					message: __("Submit this document to complete this step."),
					title: __("Great")
				});
			};
			frappe.route_hooks.after_submit = callback;
		} else {
			frappe.route_hooks.after_save = callback;
		}

		frappe.set_route(`Form/${step.reference_document}/New ${step.reference_document} 1`);
	}

	show_quick_entry(step) {
		let current_route = frappe.get_route_str();
		frappe.ui.form.make_quick_entry(
			step.reference_document,
			() => {
				if (frappe.get_route_str() != current_route) {
					let success_dialog = frappe.msgprint({
						message: __("Let's take you back to onboarding"),
						title: __("Looks Great"),
						primary_action: {
							action: () => {
								success_dialog.hide();
								frappe.set_route(current_route).then(() => {
									this.mark_complete(step);
								});
							},
							label: __("Continue"),
						},
					});

					frappe.msg_dialog.custom_onhide = () => {
						frappe.set_route(current_route).then(() => {
							this.mark_complete(step);
						});
					};
				} else {
					this.mark_complete(step);
				}
			},
			null,
			null,
			true
		);
	}

	show_video(step) {
		frappe.help.show_video(step.video_url, step.title);
		this.mark_complete(step);
	}

	mark_complete(step) {
		let $step = step.$step;

		let callback = () => {
			step.is_complete = true;
			$step.removeClass("skipped");
			$step.addClass("complete");
		};

		this.update_step_status(step, "is_complete", 1, callback);
	}

	skip_step(step) {
		let $step = step.$step;

		let callback = () => {
			step.is_skipped = true;
			$step.removeClass("complete");
			$step.addClass("skipped");
		};

		this.update_step_status(step, "is_skipped", 1, callback);
	}

	update_step_status(step, status, value, callback) {
		let icon_class = {
			is_complete: "fa-check-circle-o",
			is_skipped: "fa-check-circle-o",
		};
		//  Clear any hooks
		frappe.route_hooks = {};

		frappe
			.call("frappe.desk.desktop.update_onboarding_step", {
				name: step.name,
				field: status,
				value: value,
			})
			.then(() => {
				callback();

				let icon = step.$step.find("i.fa");
				icon.removeClass();
				icon.addClass("fa");
				icon.addClass(icon_class[status]);

				let pending = this.steps.filter((step) => {
					return !(step.is_complete || step.is_skipped);
				});

				if (pending.length == 0) {
					this.show_success();
				}
			});
	}

	show_success() {
		let success_message = this.success || __("You seem good to go!");
		let success_state_image =
			this.success_state_image ||
			"/assets/frappe/images/ui-states/success-color.png";
		let documentation = "";
		if (this.docs_url) {
			documentation = __(
				'Congratulations on completing the module setup. If you want to learn more you can refer to the documentation here.',
				[this.docs_url]
			);
		}

		let success = $(`

${success_message}

${documentation}

		`);

		if (!this.success_dialog) {
			this.success_dialog = new frappe.ui.Dialog({
				primary_action: () => {
					this.success_dialog.hide();
					// Wait for modal to close before removing widget
					setTimeout(() => {
						this.delete();
					}, 300);
				},
				primary_action_label: __("Continue"),
			});

			this.success_dialog.set_title(__("Onboarding Complete"));
			this.success_dialog.header
				.find(".indicator")
				.removeClass("hidden")
				.addClass("green");

			success.appendTo(this.success_dialog.$body);
			this.success_dialog.show();
		}
	}

	set_body() {
		this.widget.addClass("onboarding-widget-box");
		if (this.is_dismissed()) {
			this.widget.hide();
		} else {
			this.make_body();
		}
	}

	is_dismissed() {
		let dismissed = JSON.parse(
			localStorage.getItem("dismissed-onboarding") || "{}"
		);
		if (Object.keys(dismissed).includes(this.label)) {
			let last_hidden = new Date(dismissed[this.label]);
			let today = new Date();
			let diff = frappe.datetime.get_hour_diff(today, last_hidden);
			return diff < 24;
		}
		return false;
	}

	set_title(title) {
		super.set_title(title);
		if (this.subtitle) {
			let subtitle = $(
				`<div class="widget-subtitle">${this.subtitle}</div>`
			);
			subtitle.appendTo(this.title_field);
		}
	}

	set_actions() {
		this.action_area.empty();
		if (!this.user_can_dismiss) return;

		const dismiss = $(
			`<div class="small" style="cursor:pointer;">Dismiss</div>`
		);
		dismiss.on("click", () => {
			let dismissed = JSON.parse(
				localStorage.getItem("dismissed-onboarding") || "{}"
			);
			dismissed[this.label] = frappe.datetime.now_datetime();

			localStorage.setItem(
				"dismissed-onboarding",
				JSON.stringify(dismissed)
			);
			this.delete();
		});
		dismiss.appendTo(this.action_area);
	}
}
<commit_msg>feat: show message print on quick entry dialog (#10580)<commit_after>import Widget from "./base_widget.js";
import { generate_route } from "./utils";

export default class OnboardingWidget extends Widget {
	constructor(opts) {
		super(opts);
	}

	make_body() {
		this.body.addClass("grid");
		if (this.steps.length < 5) {
			this.body.addClass(`grid-rows-${this.steps.length}`);
		} else if (this.steps.length >= 5) {
			this.body.addClass("grid-rows-5");
		}
		this.steps.forEach((step) => {
			this.add_step(step);
		});
	}

	add_step(step) {
		// Make Step
		let status = "";
		let icon_class = "fa-circle-o";

		if (step.is_skipped) {
			status = "skipped";
			icon_class = "fa-check-circle-o";
		}

		if (step.is_complete) {
			status = "complete";
			icon_class = "fa-check-circle-o";
		}

		let $step = $(`

				${step.title}

`);

		step.$step = $step;

		// Add skip button
		if (!step.is_mandatory && !step.is_complete) {
			let skip_html = $(
				`<span class="ml-5 small text-muted step-skip">Skip</span>`
			);

			skip_html.appendTo($step);
			skip_html.on("click", () => {
				this.skip_step(step);
				event.stopPropagation();
			});
		}

		// Setup actions
		let actions = {
			"Watch Video": () => this.show_video(step),
			"Create Entry": () => {
				if (step.show_full_form) {
					this.create_entry(step);
				} else {
					this.show_quick_entry(step);
				}
			},
			"Show Form Tour": () => this.show_form_tour(step),
			"Update Settings": () => this.update_settings(step),
			"View Report": () => this.open_report(step),
			"Go to Page": () => this.go_to_page(step),
		};

		$step.find("#title").on("click", actions[step.action]);

		$step.appendTo(this.body);
		return $step;
	}

	go_to_page(step) {
		frappe.set_route(step.path).then(() => {
			if (step.callback_message) {
				let msg_dialog = frappe.msgprint({
					message: __(step.callback_message),
					title: __(step.callback_title),
					primary_action: {
						action: () => {
							msg_dialog.hide();
						},
						label: () => __("Continue"),
					},
					wide: true,
				});
			}
		});
	}

	open_report(step) {
		let route = generate_route({
			name: step.reference_report,
			type: "report",
			is_query_report: ["Query Report", "Script Report"].includes(
				step.report_type
			),
			doctype: step.report_reference_doctype,
		});

		let current_route = frappe.get_route();

		frappe.set_route(route).then(() => {
			let msg_dialog = frappe.msgprint({
				message: __(step.report_description),
				title: __(step.reference_report),
				primary_action: {
					action: () => {
						frappe.set_route(current_route).then(() => {
							this.mark_complete(step);
						});
						msg_dialog.hide();
					},
					label: () => __("Continue"),
				},
				secondary_action: {
					action: () => {
						msg_dialog.hide();
						frappe.set_route(current_route).then(() => {
							this.mark_complete(step);
						});
					},
					label: __("Go Back"),
				},
			});

			frappe.msg_dialog.custom_onhide = () => this.mark_complete(step);
		});
	}

	show_form_tour(step) {
		let route;
		if (step.is_single) {
			route = `Form/${step.reference_document}`;
		} else {
			route = `Form/${step.reference_document}/New ${step.reference_document}`;
		}

		let current_route = frappe.get_route();

		frappe.route_hooks = {};
		frappe.route_hooks.after_load = (frm) => {
			frm.show_tour(() => {
				let msg_dialog = frappe.msgprint({
					message: __("Let's take you back to onboarding"),
					title: __("Great Job"),
					primary_action: {
						action: () => {
							frappe.set_route(current_route).then(() => {
								this.mark_complete(step);
							});
							msg_dialog.hide();
						},
						label: () => __("Continue"),
					},
				});
			});
		};

		frappe.set_route(route);
	}

	update_settings(step) {
		let current_route = frappe.get_route();

		frappe.route_hooks = {};
		frappe.route_hooks.after_load = (frm) => {
			frm.scroll_to_field(step.field);
			frm.doc.__unsaved = true;
		};

		frappe.route_hooks.after_save = (frm) => {
			let success = false;
			let args = {};

			let value = frm.doc[step.field];
			let custom_onhide = null;

			if (value && step.value_to_validate == "%") success = true;
			if (value == step.value_to_validate) success = true;
			if (cstr(value) == cstr(step.value_to_validate)) success = true;

			if (success) {
				args.message = __("Let's take you back to onboarding");
				args.title = __("Looks Great");
				args.primary_action = {
					action: () => {
						frappe.set_route(current_route).then(() => {
							this.mark_complete(step);
						});
					},
					label: __("Continue"),
				};

				custom_onhide = () => args.primary_action.action();
			} else {
				args.message = __("Looks like you didn't change the value");
				args.title = __("Oops");
				args.secondary_action = {
					action: () => frappe.set_route(current_route),
					label: __("Go Back"),
				};

				if (!step.is_mandatory) {
					args.primary_action = {
						action: () => {
							frappe.set_route(current_route).then(() => {
								setTimeout(() => {
									this.skip_step(step);
								}, 300);
							});
						},
						label: __("Skip Step"),
					};
				}

				custom_onhide = () => args.secondary_action.action();
			}

			frappe.msgprint(args);
			frappe.msg_dialog.custom_onhide = () => custom_onhide();
		};

		frappe.set_route("Form", step.reference_document);
	}

	create_entry(step) {
		let current_route = frappe.get_route();

		frappe.route_hooks = {};
		let callback = () => {
			frappe.msgprint({
				message: __("You're doing great, let's take you back to the onboarding page."),
				title: __("Good Work 🎉"),
				primary_action: {
					action: () => {
						frappe.set_route(current_route).then(() => {
							this.mark_complete(step);
						});
					},
					label: __("Continue"),
				},
			});

			frappe.msg_dialog.custom_onhide = () => {
				this.mark_complete(step);
			};
		};

		if (step.is_submittable) {
			frappe.route_hooks.after_save = () => {
				frappe.msgprint({
					message: __("Submit this document to complete this step."),
					title: __("Great")
				});
			};
			frappe.route_hooks.after_submit = callback;
		} else {
			frappe.route_hooks.after_save = callback;
		}

		frappe.set_route(`Form/${step.reference_document}/New ${step.reference_document} 1`);
	}

	show_quick_entry(step) {
		let current_route = frappe.get_route_str();
		frappe.ui.form.make_quick_entry(
			step.reference_document,
			() => {
				if (frappe.get_route_str() != current_route) {
					let success_dialog = frappe.msgprint({
						message: __("Let's take you back to onboarding"),
						title: __("Looks Great"),
						primary_action: {
							action: () => {
								success_dialog.hide();
								frappe.set_route(current_route).then(() => {
									this.mark_complete(step);
								});
							},
							label: __("Continue"),
						},
					});

					frappe.msg_dialog.custom_onhide = () => {
						frappe.set_route(current_route).then(() => {
							this.mark_complete(step);
						});
					};
				} else {
					frappe.msgprint({
						message: __("You may continue with onboarding"),
						title: __("Looks Great")
					});
					this.mark_complete(step);
				}
			},
			null,
			null,
			true
		);
	}

	show_video(step) {
		frappe.help.show_video(step.video_url, step.title);
		this.mark_complete(step);
	}

	mark_complete(step) {
		let $step = step.$step;

		let callback = () => {
			step.is_complete = true;
			$step.removeClass("skipped");
			$step.addClass("complete");
		};

		this.update_step_status(step, "is_complete", 1, callback);
	}

	skip_step(step) {
		let $step = step.$step;

		let callback = () => {
			step.is_skipped = true;
			$step.removeClass("complete");
			$step.addClass("skipped");
		};

		this.update_step_status(step, "is_skipped", 1, callback);
	}

	update_step_status(step, status, value, callback) {
		let icon_class = {
			is_complete: "fa-check-circle-o",
			is_skipped: "fa-check-circle-o",
		};
		//  Clear any hooks
		frappe.route_hooks = {};

		frappe
			.call("frappe.desk.desktop.update_onboarding_step", {
				name: step.name,
				field: status,
				value: value,
			})
			.then(() => {
				callback();

				let icon = step.$step.find("i.fa");
				icon.removeClass();
				icon.addClass("fa");
				icon.addClass(icon_class[status]);

				let pending = this.steps.filter((step) => {
					return !(step.is_complete || step.is_skipped);
				});

				if (pending.length == 0) {
					this.show_success();
				}
			});
	}

	show_success() {
		let success_message = this.success || __("You seem good to go!");
		let success_state_image =
			this.success_state_image ||
			"/assets/frappe/images/ui-states/success-color.png";
		let documentation = "";
		if (this.docs_url) {
			documentation = __(
				'Congratulations on completing the module setup. If you want to learn more you can refer to the documentation here.',
				[this.docs_url]
			);
		}

		let success = $(`

${success_message}

${documentation}

		`);

		if (!this.success_dialog) {
			this.success_dialog = new frappe.ui.Dialog({
				primary_action: () => {
					this.success_dialog.hide();
					// Wait for modal to close before removing widget
					setTimeout(() => {
						this.delete();
					}, 300);
				},
				primary_action_label: __("Continue"),
			});

			this.success_dialog.set_title(__("Onboarding Complete"));
			this.success_dialog.header
				.find(".indicator")
				.removeClass("hidden")
				.addClass("green");

			success.appendTo(this.success_dialog.$body);
			this.success_dialog.show();
		}
	}

	set_body() {
		this.widget.addClass("onboarding-widget-box");
		if (this.is_dismissed()) {
			this.widget.hide();
		} else {
			this.make_body();
		}
	}

	is_dismissed() {
		let dismissed = JSON.parse(
			localStorage.getItem("dismissed-onboarding") || "{}"
		);
		if (Object.keys(dismissed).includes(this.label)) {
			let last_hidden = new Date(dismissed[this.label]);
			let today = new Date();
			let diff = frappe.datetime.get_hour_diff(today, last_hidden);
			return diff < 24;
		}
		return false;
	}

	set_title(title) {
		super.set_title(title);
		if (this.subtitle) {
			let subtitle = $(
				`<div class="widget-subtitle">${this.subtitle}</div>`
			);
			subtitle.appendTo(this.title_field);
		}
	}

	set_actions() {
		this.action_area.empty();
		if (!this.user_can_dismiss) return;

		const dismiss = $(
			`<div class="small" style="cursor:pointer;">Dismiss</div>`
		);
		dismiss.on("click", () => {
			let dismissed = JSON.parse(
				localStorage.getItem("dismissed-onboarding") || "{}"
			);
			dismissed[this.label] = frappe.datetime.now_datetime();

			localStorage.setItem(
				"dismissed-onboarding",
				JSON.stringify(dismissed)
			);
			this.delete();
		});
		dismiss.appendTo(this.action_area);
	}
}
<|endoftext|>


<commit_before>var _ = require('lodash')
var courses = require('./db').courses

function splitDeptNum(deptNumString) {
	// "AS/RE 230A" -> ["AS/RE 230A", "AS/RE", "AS", "RE", "230", "A"]
	// -> {depts: ['AS', 'RE'], num: 230}
	var combined = deptNumString.toUpperCase()
	var regex = /(([A-Z]+)(?=\/)(?:\/)([A-Z]+)|[A-Z]+) *([0-9]+) *([A-Z]?)/gi
	var matches = regex.exec(combined)

	return {
		dept: _.contains(matches[1], '/') ? [matches[2], matches[3]] : [matches[1]],
		num: parseInt(matches[4], 10)
	}
}

function buildDeptNum(course) {
	return course.depts.join('/') + ' ' + course.num
}

module.exports.splitDeptNum = splitDeptNum
module.exports.buildDeptNum = buildDeptNum
<commit_msg>Create hasDeptNumBetween<commit_after>var _ = require('lodash')
var courses = require('./db').courses

var hasDepartment = require('./hasDepartment')

function splitDeptNum(deptNumString) {
	// "AS/RE 230A" -> ["AS/RE 230A", "AS/RE", "AS", "RE", "230", "A"]
	// -> {depts: ['AS', 'RE'], num: 230}
	var combined = deptNumString.toUpperCase()
	var regex = /(([A-Z]+)(?=\/)(?:\/)([A-Z]+)|[A-Z]+) *([0-9]+) *([A-Z]?)/gi
	var matches = regex.exec(combined)

	return {
		dept: _.contains(matches[1], '/') ? [matches[2], matches[3]] : [matches[1]],
		num: parseInt(matches[4], 10)
	}
}

function buildDeptNum(course) {
	return course.depts.join('/') + ' ' + course.num
}

function hasDeptNumBetween(args, course) {
	var dept = args.dept
	var start = args.start
	var end = args.end

	if (_.any([dept, start, end], _.isUndefined)) {
		return false
	}

	return _.all([
		hasDepartment(course, dept),
		dept.num >= start,
		dept.num <= end
	])
}

module.exports.splitDeptNum = splitDeptNum
module.exports.buildDeptNum = buildDeptNum
module.exports.hasDeptNumBetween = hasDeptNumBetween
<|endoftext|>


<commit_before>$(function () {

    // CSS tweaks
    $('#header #nav li:last').addClass('nobg');
    $('.block_head ul').each(function () {
        $('li:first', this).addClass('nobg');
    });
    $('.block form input[type=file]').addClass('file');

    // Web stats
    $('table.stats').each(function () {

        if ($(this).attr('rel')) {
            var statsType = $(this).attr('rel');
        } else {
            var statsType = 'area';
        }

        if (statsType == 'line' || statsType == 'pie') {
            $(this).hide().visualize({
                type: statsType,
                // 'bar', 'area', 'pie', 'line'
                height: '240px',
                colors: ['#6fb9e8', '#ec8526', '#9dc453', '#ddd74c'],
                lineDots: 'double',
                interaction: true,
                multiHover: 5,
                tooltip: true,
                tooltiphtml: function (data) {
                    var html = '';
                    for (var i = 0; i < data.point.length; i++) {
                        html += '
' + data.point[i].value + ' ' + data.point[i].yLabels[0] + '
';
                    }
                    return html;
                }
            });
        } else {
            $(this).hide().visualize({
                // 'bar', 'area', 'pie', 'line'
                type: statsType,
                height: '240px',
                colors: ['#6fb9e8', '#ec8526', '#9dc453', '#ddd74c']
            });
        }
    });

    // Sort table
    $("table.sortable").tablesorter({
        headers: {
            0: {
                //sorter: false
            },
            5: {
                //sorter: false
            }
        },
        // Disabled on the 1st and 6th columns
        widgets: ['zebra']
    });

    $("table.pagesort")
      .tablesorter({ widgets: ['zebra'] })
      .tablesorterPager({ positionFixed: false, container: $("#pager") });
    $("table.pagesort2")
      .tablesorter({ widgets: ['zebra'] })
      .tablesorterPager({ positionFixed: false, container: $("#pager2") });
    $("table.pagesort4")
      .tablesorter({ widgets: ['zebra'] })
      .tablesorterPager({ positionFixed: false, container: $("#pager3") });

    $('.block table tr th.header').css('cursor', 'pointer');

    // Check / uncheck all checkboxes
    $('.check_all').click(function () {
        $(this).parents('form').find('input:checkbox').attr('checked', $(this).is(':checked'));
    });

    // Messages
    $('.block .message').hide().append('').fadeIn('slow');
    $('.block .message .close').hover(

    function () {
        $(this).addClass('hover');
    }, function () {
        $(this).removeClass('hover');
    });

    $('.block .message .close').click(function () {
        $(this).parent().fadeOut('slow', function () {
            $(this).remove();
        });
    });

    // Tabs
    $(".tab_content").hide();
    $("ul.tabs li:first-child").addClass("active").show();
    $(".block").find(".tab_content:first").show();

    $("ul.tabs li").click(function () {
        $(this).parent().find('li').removeClass("active");
        $(this).addClass("active");
        $(this).parents('.block').find(".tab_content").hide();

        var activeTab = $(this).find("a").attr("href");
        $(activeTab).show();

        // refresh visualize for IE
        $(activeTab).find('.visualize').trigger('visualizeRefresh');

        return false;
    });

    // Sidebar Tabs
    $(".sidebar_content").hide();

    if (window.location.hash && window.location.hash.match('sb')) {

        $("ul.sidemenu li a[href=" + window.location.hash + "]").parent().addClass("active").show();
        $(".block .sidebar_content#" + window.location.hash).show();
    } else {

        $("ul.sidemenu li:first-child").addClass("active").show();
        $(".block .sidebar_content:first").show();
    }

    $("ul.sidemenu li").click(function () {

        var activeTab = $(this).find("a").attr("href");
        window.location.hash = activeTab;

        $(this).parent().find('li').removeClass("active");
        $(this).addClass("active");
        $(this).parents('.block').find(".sidebar_content").hide();
        $(activeTab).show();
        return false;
    });

    // Block search
    $('.block .block_head form .text').bind('click', function () {
        $(this).attr('value', '');
    });

    // Navigation dropdown fix for IE6
    if (jQuery.browser.version.substr(0, 1) < 7) {
        $('#header #nav li').hover(

        function () {
            $(this).addClass('iehover');
        }, function () {
            $(this).removeClass('iehover');
        });
    }

});
<commit_msg>re-introduce graph width detection<commit_after>$(function () {

    // CSS tweaks
    $('#header #nav li:last').addClass('nobg');
    $('.block_head ul').each(function () {
        $('li:first', this).addClass('nobg');
    });
    $('.block form input[type=file]').addClass('file');

    // Web stats
    $('table.stats').each(function () {

        if ($(this).attr('rel')) {
            var statsType = $(this).attr('rel');
        } else {
            var statsType = 'area';
        }

        // hack to statically set width as something is broken with div width calculation - anni
        var chart_width = $(document).width() - 400;

        if (statsType == 'line' || statsType == 'pie') {
            $(this).hide().visualize({
                type: statsType,
                // 'bar', 'area', 'pie', 'line'
                width: chart_width,
                height: '240px',
                colors: ['#6fb9e8', '#ec8526', '#9dc453', '#ddd74c'],
                lineDots: 'double',
                interaction: true,
                multiHover: 5,
                tooltip: true,
                tooltiphtml: function (data) {
                    var html = '';
                    for (var i = 0; i < data.point.length; i++) {
                        html += '
' + data.point[i].value + ' ' + data.point[i].yLabels[0] + '
';
                    }
                    return html;
                }
            });
        } else {
            $(this).hide().visualize({
                // 'bar', 'area', 'pie', 'line'
                width: chart_width,
                type: statsType,
                height: '240px',
                colors: ['#6fb9e8', '#ec8526', '#9dc453', '#ddd74c']
            });
        }
    });

    // Sort table
    $("table.sortable").tablesorter({
        headers: {
            0: {
                //sorter: false
            },
            5: {
                //sorter: false
            }
        },
        // Disabled on the 1st and 6th columns
        widgets: ['zebra']
    });

    $("table.pagesort")
      .tablesorter({ widgets: ['zebra'] })
      .tablesorterPager({ positionFixed: false, container: $("#pager") });
    $("table.pagesort2")
      .tablesorter({ widgets: ['zebra'] })
      .tablesorterPager({ positionFixed: false, container: $("#pager2") });
    $("table.pagesort4")
      .tablesorter({ widgets: ['zebra'] })
      .tablesorterPager({ positionFixed: false, container: $("#pager3") });

    $('.block table tr th.header').css('cursor', 'pointer');

    // Check / uncheck all checkboxes
    $('.check_all').click(function () {
        $(this).parents('form').find('input:checkbox').attr('checked', $(this).is(':checked'));
    });

    // Messages
    $('.block .message').hide().append('').fadeIn('slow');
    $('.block .message .close').hover(

    function () {
        $(this).addClass('hover');
    }, function () {
        $(this).removeClass('hover');
    });

    $('.block .message .close').click(function () {
        $(this).parent().fadeOut('slow', function () {
            $(this).remove();
        });
    });

    // Tabs
    $(".tab_content").hide();
    $("ul.tabs li:first-child").addClass("active").show();
    $(".block").find(".tab_content:first").show();

    $("ul.tabs li").click(function () {
        $(this).parent().find('li').removeClass("active");
        $(this).addClass("active");
        $(this).parents('.block').find(".tab_content").hide();

        var activeTab = $(this).find("a").attr("href");
        $(activeTab).show();

        // refresh visualize for IE
        $(activeTab).find('.visualize').trigger('visualizeRefresh');

        return false;
    });

    // Sidebar Tabs
    $(".sidebar_content").hide();

    if (window.location.hash && window.location.hash.match('sb')) {

        $("ul.sidemenu li a[href=" + window.location.hash + "]").parent().addClass("active").show();
        $(".block .sidebar_content#" + window.location.hash).show();
    } else {

        $("ul.sidemenu li:first-child").addClass("active").show();
        $(".block .sidebar_content:first").show();
    }

    $("ul.sidemenu li").click(function () {

        var activeTab = $(this).find("a").attr("href");
        window.location.hash = activeTab;

        $(this).parent().find('li').removeClass("active");
        $(this).addClass("active");
        $(this).parents('.block').find(".sidebar_content").hide();
        $(activeTab).show();
        return false;
    });

    // Block search
    $('.block .block_head form .text').bind('click', function () {
        $(this).attr('value', '');
    });

    // Navigation dropdown fix for IE6
    if (jQuery.browser.version.substr(0, 1) < 7) {
        $('#header #nav li').hover(

        function () {
            $(this).addClass('iehover');
        }, function () {
            $(this).removeClass('iehover');
        });
    }

});
<|endoftext|>


<commit_before>
/**
 * shows a dialog to get the table exported
 * new ExportTableDialog({
 *  table: table_model
 * })
 *
 */
cdb.admin.ExportTableDialog = cdb.admin.BaseDialog.extend({

  events: cdb.core.View.extendEvents({
    'click .export:not(.disabled)': 'export'
  }),

  formats: [
    {format: 'csv', fetcher: 'fetchCSV', geomRequired: false},
    {format: 'shp', fetcher: 'fetch', geomRequired: true},
    {format: 'kml', fetcher: 'fetch', geomRequired: true},
    {format: 'svg', fetcher: 'fetchSVG', geomRequired: true},
    {format: 'geojson', fetcher: 'fetch', geomRequired: true}
  ],

  initialize: function() {
    _.extend(this.options, {
      title: "Select your file type",
      description: '',
      template_name: 'common/views/dialog_base',
      clean_on_hide: true,
      ok_button_classes: "button grey",
      ok_title: "",
      modal_type: "",
      width: 510,
      modal_class: 'export_table_dialog',
      include_footer: false,
      table_id: this.model.id
    });
    this.constructor.__super__.initialize.apply(this);
    _.bindAll(this, 'export');
    this.baseUrl = this.options.config.sql_api_protocol + '://' + this.options.config.sql_api_domain
      + ':'
      + this.options.config.sql_api_port
      + '/api/v1/sql';
  },

  getFormat: function(format) {
    for(var n in this.formats) {
      if(this.formats[n].format === format) {
        return this.formats[n]
      }
    }
  },

  export: function(ev) {
    this.killEvent(ev);
    var $button = $(ev.currentTarget);
    var formatName = $button.data('format');
    var format = this.getFormat(formatName);
    this[format.fetcher](formatName);
  },

  isGeoreferenced: function() {
    var currentSchema = this.model.get('schema');
    // if we have "the_geom" in our current schema, returnstrue
    for(var n in currentSchema) {
      if(currentSchema[n][0] === 'the_geom') {
        return true;
      }
    }
    return false;
  },

  getBaseOptions: function() {
    var options = {}
    options.filename = this.model.get('name');
    if(this.model.sqlView) {
      options.filename = 'cartodb_query';
    }

    if(this.options.user_data) {
      options.api_key = this.options.user_data.api_key;
    }
    return options;
  },

  getPlainSql: function() {
    if(this.options.sql) {
      sql = this.options.sql;
    } else {
      if(this.model.sqlView) {
        sql = this.model.sqlView.getSQL();
      } else {
        sql = "select * from " + this.model.get('name')
      }
    }
    return sql;
  },

  getGeomFilteredSql: function() {
    var sql = this.getPlainSql();
    var currentSchema = this.model.get('schema');
    // if we have "the_geom" in our current schema, we apply a custom sql
    if(this.isGeoreferenced()) {
      return "SELECT *, CASE WHEN GeometryType(the_geom)='POINT' THEN ST_X(the_geom) ELSE ST_X(ST_PointOnSurface(the_geom)) END as longitude, CASE WHEN GeometryType(the_geom)='POINT' THEN ST_Y(the_geom) ELSE ST_Y(ST_PointOnSurface(the_geom)) END as latitude, ST_AsGeoJSON(the_geom,5) as geojson FROM ("+ sql + ") as subq";
    } // if not, we apply regular sql
    return sql;

  },

  _fetch: function(options, sql) {
    var self = this;
    this.$('.format').val(options.format);
    this.$('.q').val(sql);
    this.$('.filename').val(options.filename);
    this.$('.api_key').val(options.api_key);
    this.$('.generating').fadeIn();
    this.$('.geospatial').fadeOut();
    this.$('form').submit();
    this.$('.db').attr('disabled', 'disabled');
    this.$('.skipfields').attr('disabled', 'disabled');
  },
  fetch: function(formatName) {
    var options = this.getBaseOptions();
    options.format = formatName;
    var sql = this.getPlainSql();
    this._fetch(options, sql);
  },
  fetchCSV: function(formatName) {
    var options = this.getBaseOptions();
    options.format = formatName;
    var sql = this.getGeomFilteredSql();
    this.$('.skipfields').removeAttr('disabled');
    this._fetch(options, sql);
  },
  fetchSVG: function(){
    this.$('.db').removeAttr('disabled');
    this.fetch();
  },
  render_content: function() {
    console.log(this.isGeoreferenced());
    return this.getTemplate('common/views/export_table_dialog')({
      formats:this.formats,
      url: this.baseUrl,
      hasGeom: this.isGeoreferenced()
    });
  }
});
<commit_msg>doc added<commit_after>
/**
 * shows a dialog to get the table exported
 * new ExportTableDialog({
 *  table: table_model
 * })
 *
 */
cdb.admin.ExportTableDialog = cdb.admin.BaseDialog.extend({

  events: cdb.core.View.extendEvents({
    'click .export:not(.disabled)': 'export'
  }),

  /**
   * Allowed formats on the exporter
   * @type {Array}
   */
  formats: [
    {format: 'csv', fetcher: 'fetchCSV', geomRequired: false},
    {format: 'shp', fetcher: 'fetch', geomRequired: true},
    {format: 'kml', fetcher: 'fetch', geomRequired: true},
    {format: 'svg', fetcher: 'fetchSVG', geomRequired: true},
    {format: 'geojson', fetcher: 'fetch', geomRequired: true}
  ],

  initialize: function() {
    _.extend(this.options, {
      title: "Select your file type",
      description: '',
      template_name: 'common/views/dialog_base',
      clean_on_hide: true,
      ok_button_classes: "button grey",
      ok_title: "",
      modal_type: "",
      width: 510,
      modal_class: 'export_table_dialog',
      include_footer: false,
      table_id: this.model.id
    });
    this.constructor.__super__.initialize.apply(this);
    _.bindAll(this, 'export');
    this.baseUrl = this.options.config.sql_api_protocol + '://' + this.options.config.sql_api_domain
      + ':'
      + this.options.config.sql_api_port
      + '/api/v1/sql';
  },

  /**
   * search a format based on its name in the format array
   * @param  {string} format Format name
   * @return {Object}
   */
  getFormat: function(format) {
    for(var n in this.formats) {
      if(this.formats[n].format === format) {
        return this.formats[n]
      }
    }
  },

  /**
   * Answer to button event and lauchn the export method associated to that format
   * @param  {Event} ev
   */
  export: function(ev) {
    this.killEvent(ev);
    var $button = $(ev.currentTarget);
    var formatName = $button.data('format');
    var format = this.getFormat(formatName);
    this[format.fetcher](formatName);
  },

  /**
   * Checks if the table has "the_geom" in the current view
   * @return {Boolean}
   */
  isGeoreferenced: function() {
    var currentSchema = this.model.get('schema');
    // if we have "the_geom" in our current schema, returnstrue
    for(var n in currentSchema) {
      if(currentSchema[n][0] === 'the_geom') {
        return true;
      }
    }
    return false;
  },

  /**
   * Create a dictionary with the options shared between all the methods
   * @return {Object}
   */
  getBaseOptions: function() {
    var options = {}
    options.filename = this.model.get('name');
    if(this.model.sqlView) {
      options.filename = 'cartodb_query';
    }

    if(this.options.user_data) {
      options.api_key = this.options.user_data.api_key;
    }
    return options;
  },

  /**
   * Returns the base sql to retrieve the data
   * @return {string}
   */
  getPlainSql: function() {
    if(this.options.sql) {
      sql = this.options.sql;
    } else {
      if(this.model.sqlView) {
        sql = this.model.sqlView.getSQL();
      } else {
        sql = "select * from " + this.model.get('name')
      }
    }
    return sql;
  },

  /**
   * Returns a specific sql filtered by the_geom, used on CSV exports
   * @return {string}
   */
  getGeomFilteredSql: function() {
    var sql = this.getPlainSql();
    var currentSchema = this.model.get('schema');
    // if we have "the_geom" in our current schema, we apply a custom sql
    if(this.isGeoreferenced()) {
      return "SELECT *, CASE WHEN GeometryType(the_geom)='POINT' THEN ST_X(the_geom) ELSE ST_X(ST_PointOnSurface(the_geom)) END as longitude, CASE WHEN GeometryType(the_geom)='POINT' THEN ST_Y(the_geom) ELSE ST_Y(ST_PointOnSurface(the_geom)) END as latitude, ST_AsGeoJSON(the_geom,5) as geojson FROM ("+ sql + ") as subq";
    } // if not, we apply regular sql
    return sql;

  },

  /**
   * Populates the hidden form with the format related values and submit them to get the file
   * @param  {Object} options Base options
   * @param  {String} sql Sql of the document to be retrieved
   */
  _fetch: function(options, sql) {
    var self = this;
    this.$('.format').val(options.format);
    this.$('.q').val(sql);
    this.$('.filename').val(options.filename);
    this.$('.api_key').val(options.api_key);
    this.$('.generating').fadeIn();
    this.$('.geospatial').fadeOut();
    this.$('form').submit();
    this.$('.db').attr('disabled', 'disabled');
    this.$('.skipfields').attr('disabled', 'disabled');
  },

  /**
   * Base fetch, for the formats that don't require special threatment
   * @param  {String} formatName
   */
  fetch: function(formatName) {
    var options = this.getBaseOptions();
    options.format = formatName;
    var sql = this.getPlainSql();
    this._fetch(options, sql);
  },
  /**
   * Gets the options needed for csv format and fetch the document
   * @param  {String} formatName
   */
  fetchCSV: function(formatName) {
    var options = this.getBaseOptions();
    options.format = formatName;
    var sql = this.getGeomFilteredSql();
    this.$('.skipfields').removeAttr('disabled');
    this._fetch(options, sql);
  },
  /**
   * Gets the options needed for svg format and fetch the document
   * @param  {String} formatName
   */
  fetchSVG: function(){
    this.$('.db').removeAttr('disabled');
    this.fetch();
  },
  /**
   * Returns the html populated with current data
   * @return {String}
   */
  render_content: function() {
    console.log(this.isGeoreferenced());
    return this.getTemplate('common/views/export_table_dialog')({
      formats:this.formats,
      url: this.baseUrl,
      hasGeom: this.isGeoreferenced()
    });
  }
});
<|endoftext|>


<commit_before>/* eslint-disable max-statements */

// Client-side routing

var account = require('../stores/account');

var AdminUsersView = require('../components/Admin/Users');
var AdminUserView = require('../components/Admin/Users/User');
var BatchView = require('../components/Batch');
var CardView = require('../components/Card');
var ChangePasswordView = require('../components/ChangePassword');
var Error401View = require('../components/Error401');
var Error404View = require('../components/Error404');
var EventsView = require('../components/Events');
var ExportView = require('../components/Export');
var ImportView = require('../components/Import');
var InviteView = require('../components/Invite');
var LocationView = require('../components/Location');
var LoginView = require('../components/Login');
var BatchOutcomeView = require('../components/BatchOutcome');
var PaymentsView = require('../components/Payments');
var PaymentsAdminView = require('../components/PaymentsAdmin');
var ResetPasswordView = require('../components/ResetPassword');
var SearchView = require('../components/Search');
var SignupView = require('../components/Signup');
var StatisticsView = require('../components/Statistics');
var UsersView = require('../components/Users');
var UserView = require('../components/User');

// Help in remembering original url if redirect to login page is required.
var AfterLogin = require('./lib/AfterLogin');

var page = require('page');
var queryString = require('qs');
var emitter = require('component-emitter');

// Emit 'map_activated' so that map knows when to pan back to original state.
emitter(exports);

exports.show = function (path) {
  // For example:
  //   routes.show('/locations/' + location._id);
  return page.show(path);
};

exports.route = function () {

  // Init

  // A card is used to display content.
  var card = new CardView();
  card.bind($('#card-layer'));
  // When card is closed, user always returns to map.
  card.on('closed', function () {
    page('/');
  });

  // Handle paths where to redirect after login.
  var afterLogin = new AfterLogin();

  // Middleware
  var adminOnly = function (context, next) {
    if (account.isAdmin()) {
      return next();
    }
    var view = new Error401View();
    card.open(view, 'page');
  };

  ///////////////////////
  // Public routes first.

  page('*', function parseQueryString(context, next) {
    // Note: context.query does not have prototype. Bastard.
    var q = queryString.parse(context.querystring);

    // If querystring is empty, parse returns an object without properties.
    // Tested it.
    context.query = q;

    return next();
  });

  page('/login', function () {
    // Logout should be immediate; no reason to show progress bar.
    account.logout(function () {
      var view = new LoginView(function onSuccess() {
        // After successful login, go to original path.
        page.show(afterLogin.get());
        // Reset for another login during the same session.
        afterLogin.reset();
      });
      card.open(view, 'full');
    });
  });

  page('/reset/:token', function (context) {
    var token = context.params.token;
    var view = new ResetPasswordView(token, function success() {
      page.show('/login');
    });
    card.open(view, 'full');
  });

  page('/signup/:token', function (context) {
    var token = context.params.token;
    var view = new SignupView(token, function success() {
      page.show('/login');
    });
    card.open(view, 'full');
  });

  // Backwards compatiblity with v1 invite URLs
  page('*', function (context, next) {
    var q = context.query;

    if ('invite' in q) {
      return page.show('/signup/' + q.invite);
    }  // else

    if ('reset' in q) {
      return page.show('/reset/' + q.reset);
    }  // else

    return next();
  });

  /////////////////////////////
  // Routes that require login
  //

  page('*', function (context, next) {
    // If not logged in then show login form.

    if (account.isLoggedIn()) {
      return next();
    }

    // Remember original requested path and redirect to it after login
    afterLogin.set(context);

    page.show('/login');
  });

  page('/', function () {
    // Map is always open on the background.
    // Infinite loop prevention:
    //   Do not emit 'closed' event because it causes redirection to '/'
    var silent = true;
    card.close(silent);
    exports.emit('map_routed');
  });

  page('/export', function () {
    card.open(new ExportView());
  });

  page('/import', function () {
    card.open(new ImportView());
  });

  page('/import/:batchId/outcome', function (ctx) {
    card.open(new BatchOutcomeView(ctx.params.batchId));
  });

  page('/import/:batchId', function (ctx) {
    card.open(new BatchView(ctx.params.batchId));
  });

  page('/latest', function () {
    card.open(new EventsView());
  });

  page('/locations/:id', function (ctx) {
    var view = new LocationView(ctx.params.id);
    card.open(view);

    // Inform that location page has loaded. Map will pan so that
    // the location becomes centered at the visible portion.
    view.once('idle', function (location) {
      exports.emit('location_routed', location);
    });
  });

  page('/password', function () {
    var view = new ChangePasswordView();
    card.open(view, 'page');
  });

  page('/payments', function () {
    var view = new PaymentsView();
    card.open(view, 'page');
  });

  page('/search', function (ctx) {
    var view = new SearchView(ctx.query);
    card.open(view);
  });

  page('/users', function () {
    var view = new UsersView();
    card.open(view);
  });

  page('/users/:username', function (ctx) {
    var view = new UserView(ctx.params.username);
    card.open(view);
  });

  //////////////////
  // Routes that require admin. Note the adminOnly middleware.
  //

  page('/admin/users', adminOnly, function () {
    var view = new AdminUsersView();
    card.open(view);
  });

  page('/admin/users/:username', adminOnly, function (ctx) {
    var view = new AdminUserView(ctx.params.username);
    card.open(view);
  });

  page('/invite', adminOnly, function () {
    var view = new InviteView();
    card.open(view);
  });

  page('/payments/admin', adminOnly, function () {
    var view = new PaymentsAdminView();
    card.open(view);
  });

  page('/statistics', adminOnly, function () {
    var view = new StatisticsView();
    card.open(view);
  });

  // Catch all

  page('*', function () {
    // Page not found.
    var view = new Error404View();
    card.open(view, 'page');
  });

  page.start();
};
<commit_msg>Update mapstate via url query params<commit_after>/* eslint-disable max-statements */

// Client-side routing

var account = require('../stores/account');
var mapStateStore = require('../stores/mapstate');

var AdminUsersView = require('../components/Admin/Users');
var AdminUserView = require('../components/Admin/Users/User');
var BatchView = require('../components/Batch');
var CardView = require('../components/Card');
var ChangePasswordView = require('../components/ChangePassword');
var Error401View = require('../components/Error401');
var Error404View = require('../components/Error404');
var EventsView = require('../components/Events');
var ExportView = require('../components/Export');
var ImportView = require('../components/Import');
var InviteView = require('../components/Invite');
var LocationView = require('../components/Location');
var LoginView = require('../components/Login');
var BatchOutcomeView = require('../components/BatchOutcome');
var PaymentsView = require('../components/Payments');
var PaymentsAdminView = require('../components/PaymentsAdmin');
var ResetPasswordView = require('../components/ResetPassword');
var SearchView = require('../components/Search');
var SignupView = require('../components/Signup');
var StatisticsView = require('../components/Statistics');
var UsersView = require('../components/Users');
var UserView = require('../components/User');

// Help in remembering original url if redirect to login page is required.
var AfterLogin = require('./lib/AfterLogin');

var page = require('page');
var queryString = require('qs');
var emitter = require('component-emitter');

// Emit 'map_activated' so that map knows when to pan back to original state.
emitter(exports);

exports.show = function (path) {
  // For example:
  //   routes.show('/locations/' + location._id);
  return page.show(path);
};

exports.route = function () {

  // Init

  // A card is used to display content.
  var card = new CardView();
  card.bind($('#card-layer'));
  // When card is closed, user always returns to map.
  card.on('closed', function () {
    page('/');
  });

  // Handle paths where to redirect after login.
  var afterLogin = new AfterLogin();

  // Middleware
  var adminOnly = function (context, next) {
    if (account.isAdmin()) {
      return next();
    }
    var view = new Error401View();
    card.open(view, 'page');
  };

  ///////////////////////
  // Public routes first.

  page('*', function parseQueryString(context, next) {
    // Note: context.query does not have prototype. Bastard.
    var q = queryString.parse(context.querystring);

    // If querystring is empty, parse returns an object without properties.
    // Tested it.
    context.query = q;

    return next();
  });

  page('/login', function () {
    // Logout should be immediate; no reason to show progress bar.
    account.logout(function () {
      var view = new LoginView(function onSuccess() {
        // After successful login, go to original path.
        page.show(afterLogin.get());
        // Reset for another login during the same session.
        afterLogin.reset();
      });
      card.open(view, 'full');
    });
  });

  page('/reset/:token', function (context) {
    var token = context.params.token;
    var view = new ResetPasswordView(token, function success() {
      page.show('/login');
    });
    card.open(view, 'full');
  });

  page('/signup/:token', function (context) {
    var token = context.params.token;
    var view = new SignupView(token, function success() {
      page.show('/login');
    });
    card.open(view, 'full');
  });

  // Backwards compatiblity with v1 invite URLs
  page('*', function (context, next) {
    var q = context.query;

    if ('invite' in q) {
      return page.show('/signup/' + q.invite);
    }  // else

    if ('reset' in q) {
      return page.show('/reset/' + q.reset);
    }  // else

    return next();
  });

  /////////////////////////////
  // Routes that require login
  //

  page('*', function (context, next) {
    // If not logged in then show login form.

    if (account.isLoggedIn()) {
      return next();
    }

    // Remember original requested path and redirect to it after login
    afterLogin.set(context);

    page.show('/login');
  });

  page('*', function (context, next) {
    // Recenter map to possible query parameters.
    //
    var q = context.query;

    if (q.lat || q.lng || q.zoom) {
      var s = {};
      if (q.lat) {
        s.lat = parseFloat(q.lat);
      }
      if (q.lng) {
        s.lng = parseFloat(q.lng);
      }
      if (q.zoom) {
        s.zoom = parseInt(q.zoom, 10);
      }
      mapStateStore.update(s);
    }

    return next();
  });

  page('/', function () {
    // Map is always open on the background.
    // Infinite loop prevention:
    //   Do not emit 'closed' event because it causes redirection to '/'
    var silent = true;
    card.close(silent);
    exports.emit('map_routed');
  });

  page('/export', function () {
    card.open(new ExportView());
  });

  page('/import', function () {
    card.open(new ImportView());
  });

  page('/import/:batchId/outcome', function (ctx) {
    card.open(new BatchOutcomeView(ctx.params.batchId));
  });

  page('/import/:batchId', function (ctx) {
    card.open(new BatchView(ctx.params.batchId));
  });

  page('/latest', function () {
    card.open(new EventsView());
  });

  page('/locations/:id', function (ctx) {
    var view = new LocationView(ctx.params.id);
    card.open(view);

    // Inform that location page has loaded. Map will pan so that
    // the location becomes centered at the visible portion.
    view.once('idle', function (location) {
      exports.emit('location_routed', location);
    });
  });

  page('/password', function () {
    var view = new ChangePasswordView();
    card.open(view, 'page');
  });

  page('/payments', function () {
    var view = new PaymentsView();
    card.open(view, 'page');
  });

  page('/search', function (ctx) {
    var view = new SearchView(ctx.query);
    card.open(view);
  });

  page('/users', function () {
    var view = new UsersView();
    card.open(view);
  });

  page('/users/:username', function (ctx) {
    var view = new UserView(ctx.params.username);
    card.open(view);
  });

  //////////////////
  // Routes that require admin. Note the adminOnly middleware.
  //

  page('/admin/users', adminOnly, function () {
    var view = new AdminUsersView();
    card.open(view);
  });

  page('/admin/users/:username', adminOnly, function (ctx) {
    var view = new AdminUserView(ctx.params.username);
    card.open(view);
  });

  page('/invite', adminOnly, function () {
    var view = new InviteView();
    card.open(view);
  });

  page('/payments/admin', adminOnly, function () {
    var view = new PaymentsAdminView();
    card.open(view);
  });

  page('/statistics', adminOnly, function () {
    var view = new StatisticsView();
    card.open(view);
  });

  // Catch all

  page('*', function () {
    // Page not found.
    var view = new Error404View();
    card.open(view, 'page');
  });

  page.start();
};
<|endoftext|>


<commit_before>/**
 * guy 表示一行数据，通过position来定位位置的数据
 * @class BI.Text
 * @extends BI.Single
 */
!(function () {
    BI.Text = BI.inherit(BI.Single, {

        props: {
            baseCls: "bi-text",
            textAlign: "left",
            whiteSpace: "normal",
            lineHeight: null,
            handler: null, // 如果传入handler,表示处理文字的点击事件，不是区域的
            hgap: 0,
            vgap: 0,
            lgap: 0,
            rgap: 0,
            tgap: 0,
            bgap: 0,
            text: "",
            py: "",
            highLight: false
        },

        render: function () {
            var self = this, o = this.options;
            if (o.hgap + o.lgap > 0) {
                this.element.css({
                    "padding-left": o.hgap + o.lgap + "px"
                });
            }
            if (o.hgap + o.rgap > 0) {
                this.element.css({
                    "padding-right": o.hgap + o.rgap + "px"
                });
            }
            if (o.vgap + o.tgap > 0) {
                this.element.css({
                    "padding-top": o.vgap + o.tgap + "px"
                });
            }
            if (o.vgap + o.bgap > 0) {
                this.element.css({
                    "padding-bottom": o.vgap + o.bgap + "px"
                });
            }
            if (BI.isNumber(o.height)) {
                this.element.css({lineHeight: o.height + "px"});
            }
            if (BI.isNumber(o.lineHeight)) {
                this.element.css({lineHeight: o.lineHeight + "px"});
            }
            if (BI.isWidthOrHeight(o.maxWidth)) {
                this.element.css({maxWidth: o.maxWidth});
            }
            this.element.css({
                textAlign: o.textAlign,
                whiteSpace: this._getTextWrap(),
                textOverflow: o.whiteSpace === "nowrap" ? "ellipsis" : "",
                overflow: o.whiteSpace === "nowrap" ? "" : (BI.isWidthOrHeight(o.height) ? "auto" : "")
            });
            if (o.handler && o.handler !== BI.emptyFn) {
                this.text = BI.createWidget({
                    type: "bi.layout",
                    tagName: "span"
                });
                this.text.element.click(function () {
                    o.handler(self.getValue());
                });
                BI.createWidget({
                    type: "bi.default",
                    element: this,
                    items: [this.text]
                });
            } else {
                this.text = this;
            }

            var text = this._getShowText();
            if (BI.isKey(text)) {
                this.setText(text);
            } else if (BI.isKey(o.value)) {
                this.setText(o.value);
            }
            if (BI.isKey(o.keyword)) {
                this.doRedMark(o.keyword);
            }
            if (o.highLight) {
                this.doHighLight();
            }
        },

        _getTextWrap: function () {
            var o = this.options;
            switch (o.whiteSpace) {
                case "nowrap":
                    return "pre";
                case "normal":
                default:
                    return "pre-wrap";
            }
        },

        _getShowText: function () {
            var o = this.options;
            var text = BI.isFunction(o.text) ? o.text() : o.text;
            text = BI.isKey(text) ? text : o.value;
            return BI.Text.formatText(text + "");
        },

        doRedMark: function (keyword) {
            var o = this.options;
            // render之后做的doredmark,这个时候虽然标红了，但是之后text mounted执行的时候并没有keyword
            o.keyword = keyword;
            this.text.element.__textKeywordMarked__(this._getShowText(), keyword, o.py);
        },

        unRedMark: function () {
            var o = this.options;
            o.keyword = "";
            this.text.element.__textKeywordMarked__(this._getShowText(), "", o.py);
        },

        doHighLight: function () {
            this.text.element.addClass("bi-high-light");
        },

        unHighLight: function () {
            this.text.element.removeClass("bi-high-light");
        },

        setValue: function (text) {
            BI.Text.superclass.setValue.apply(this, arguments);
            if (!this.isReadOnly()) {
                this.setText(text);
            }
        },

        setStyle: function (css) {
            this.text.element.css(css);
        },

        setText: function (text) {
            BI.Text.superclass.setText.apply(this, arguments);
            //  为textContext赋值为undefined时在ie和edge下会真的显示undefined
            this.options.text = BI.isNotNull(text) ? text : "";
            this.doRedMark(this.options.keyword);
        }
    });
    var formatters = [];
    BI.Text.addTextFormatter = function (formatter) {
        formatters.push(formatter);
    };
    BI.Text.formatText = function (text) {
        for (var i = 0, len = formatters.length; i < len; i++) {
            text = formatters[i](text);
        }
        return text;
    };
    BI.shortcut("bi.text", BI.Text);
}());

<commit_msg>bugfix<commit_after>/**
 * guy 表示一行数据，通过position来定位位置的数据
 * @class BI.Text
 * @extends BI.Single
 */
!(function () {
    BI.Text = BI.inherit(BI.Single, {

        props: {
            baseCls: "bi-text",
            textAlign: "left",
            whiteSpace: "normal",
            lineHeight: null,
            handler: null, // 如果传入handler,表示处理文字的点击事件，不是区域的
            hgap: 0,
            vgap: 0,
            lgap: 0,
            rgap: 0,
            tgap: 0,
            bgap: 0,
            text: "",
            py: "",
            highLight: false
        },

        render: function () {
            var self = this, o = this.options;
            if (o.hgap + o.lgap > 0) {
                this.element.css({
                    "padding-left": o.hgap + o.lgap + "px"
                });
            }
            if (o.hgap + o.rgap > 0) {
                this.element.css({
                    "padding-right": o.hgap + o.rgap + "px"
                });
            }
            if (o.vgap + o.tgap > 0) {
                this.element.css({
                    "padding-top": o.vgap + o.tgap + "px"
                });
            }
            if (o.vgap + o.bgap > 0) {
                this.element.css({
                    "padding-bottom": o.vgap + o.bgap + "px"
                });
            }
            if (BI.isNumber(o.height)) {
                this.element.css({lineHeight: o.height + "px"});
            }
            if (BI.isNumber(o.lineHeight)) {
                this.element.css({lineHeight: o.lineHeight + "px"});
            }
            if (BI.isWidthOrHeight(o.maxWidth)) {
                this.element.css({maxWidth: o.maxWidth});
            }
            this.element.css({
                textAlign: o.textAlign,
                whiteSpace: this._getTextWrap(),
                textOverflow: o.whiteSpace === "nowrap" ? "ellipsis" : "",
                overflow: o.whiteSpace === "nowrap" ? "" : (BI.isWidthOrHeight(o.height) ? "auto" : "")
            });
            if (o.handler && o.handler !== BI.emptyFn) {
                this.text = BI.createWidget({
                    type: "bi.layout",
                    tagName: "span"
                });
                this.text.element.click(function () {
                    o.handler(self.getValue());
                });
                BI.createWidget({
                    type: "bi.default",
                    element: this,
                    items: [this.text]
                });
            } else {
                this.text = this;
            }

            var text = this._getShowText();
            if (BI.isKey(text)) {
                this.setText(text);
            } else if (BI.isKey(o.value)) {
                this.setText(o.value);
            }
            if (BI.isKey(o.keyword)) {
                this.doRedMark(o.keyword);
            }
            if (o.highLight) {
                this.doHighLight();
            }
        },

        _getTextWrap: function () {
            var o = this.options;
            switch (o.whiteSpace) {
                case "nowrap":
                    return "pre";
                case "normal":
                default:
                    return "pre-wrap";
            }
        },

        _getShowText: function () {
            var o = this.options;
            var text = BI.isFunction(o.text) ? o.text() : o.text;
            text = BI.isKey(text) ? text : o.value;
            return BI.Text.formatText(text + "");
        },

        _doRedMark: function (keyword) {
            var o = this.options;
            // render之后做的doredmark,这个时候虽然标红了，但是之后text mounted执行的时候并没有keyword
            o.keyword = keyword;
            this.text.element.__textKeywordMarked__(this._getShowText(), keyword, o.py);
        },

        doRedMark: function (keyword) {
            if (BI.isKey(this.options.keyword)) {
                this._doRedMark(keyword);
            }
        },

        unRedMark: function () {
            var o = this.options;
            o.keyword = "";
            this.text.element.__textKeywordMarked__(this._getShowText(), "", o.py);
        },

        doHighLight: function () {
            this.text.element.addClass("bi-high-light");
        },

        unHighLight: function () {
            this.text.element.removeClass("bi-high-light");
        },

        setValue: function (text) {
            BI.Text.superclass.setValue.apply(this, arguments);
            if (!this.isReadOnly()) {
                this.setText(text);
            }
        },

        setStyle: function (css) {
            this.text.element.css(css);
        },

        setText: function (text) {
            BI.Text.superclass.setText.apply(this, arguments);
            //  为textContext赋值为undefined时在ie和edge下会真的显示undefined
            this.options.text = BI.isNotNull(text) ? text : "";
            this._doRedMark(this.options.keyword);
        }
    });
    var formatters = [];
    BI.Text.addTextFormatter = function (formatter) {
        formatters.push(formatter);
    };
    BI.Text.formatText = function (text) {
        for (var i = 0, len = formatters.length; i < len; i++) {
            text = formatters[i](text);
        }
        return text;
    };
    BI.shortcut("bi.text", BI.Text);
}());

<|endoftext|>