diff --git a/.babelrc b/.babelrc new file mode 100644 index 000000000..af0f0c3d3 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015"] +} \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index c10f3cde9..fa33de0ff 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,11 +1,14 @@ { "env": { "jquery": true, - "browser": true, + "browser": true }, "extends": "airbnb-base", "globals": { "Bloodhound": false, + "layout_resizer": false, + "set_typeahead": false, + "open_close_icon": false }, "plugins": [ "import" diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 96fd566a7..a7d5f7934 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -1,29 +1,35 @@ // jQuery -window.jQuery = require('jquery'); -require('jquery-ujs'); +import jQuery from 'jquery'; + +window.jQuery = jQuery; +window.$ = jQuery; + +import 'jquery-ujs'; // Bootstrap -require('bootstrap/js/transition'); -require('bootstrap/js/tab'); -require('bootstrap/js/tooltip'); -require('bootstrap/js/popover'); +import 'bootstrap/js/transition'; +import 'bootstrap/js/tab'; +import 'bootstrap/js/tooltip'; +import 'bootstrap/js/popover'; // Life it up -require('vendor/lifeitup_layout'); +import 'vendor/lifeitup_layout'; // NOTE: should be removed in the future -require('vendor/bootstrap-typeahead'); +import 'vendor/bootstrap-typeahead'; // Require tree. // NOTE: This should be moved into proper modules. -require('./alert'); -require('./auth/cover'); -require('./auth/registrations'); -require('./bootstrap'); -require('./dashboard'); -require('./includes/open_close_icon'); -require('./includes/set_typehead'); -require('./namespaces'); -require('./open_search'); -require('./repositories'); -require('./teams'); +import './alert'; +import './bootstrap'; +import './dashboard'; +import './includes/open_close_icon'; +import './includes/set_typehead'; +import './namespaces'; +import './open_search'; +import './repositories'; +import './teams'; + +// new modules structure +import './modules/users'; + diff --git a/app/assets/javascripts/auth/cover.js b/app/assets/javascripts/auth/cover.js deleted file mode 100644 index e2418d03f..000000000 --- a/app/assets/javascripts/auth/cover.js +++ /dev/null @@ -1,8 +0,0 @@ -jQuery(function ($) { - var rndNum; - - if ($('body section.sign-up, body section.login').length) { - rndNum = Math.floor((Math.random() * 2) + 1); - $('body').addClass('massive-background-' + rndNum).hide().fadeIn(1000); - } -}); diff --git a/app/assets/javascripts/auth/registrations.js b/app/assets/javascripts/auth/registrations.js deleted file mode 100644 index c91c4f123..000000000 --- a/app/assets/javascripts/auth/registrations.js +++ /dev/null @@ -1,55 +0,0 @@ -/* global layout_resizer */ - -jQuery(function ($) { - var email = $('#user_email').val(); - var display = $('#user_display_name').val(); - - $('#user_email').keyup(function () { - var val = $('#user_email').val(); - var dname = $('#user_display_name').val(); - - if (dname === display && (val === email || val === '')) { - $('#edit_user.profile .btn').attr('disabled', 'disabled'); - } else { - $('#edit_user.profile .btn').removeAttr('disabled'); - } - }); - - $('#user_display_name').keyup(function () { - var val = $('#user_display_name').val(); - var em = $('#user_email').val(); - - if (val === display && (em === email || em === '')) { - $('#edit_user.profile .btn').attr('disabled', 'disabled'); - } else { - $('#edit_user.profile .btn').removeAttr('disabled'); - } - }); - - $('#edit_user.password .form-control').keyup(function () { - var current = $('#user_current_password').val(); - var password = $('#user_password').val(); - var confirm = $('#user_password_confirmation').val(); - - if (current !== '' && password !== '' && confirm !== '' && password === confirm) { - $('#edit_user.password .btn').removeAttr('disabled'); - } else { - $('#edit_user.password .btn').attr('disabled', 'disabled'); - } - }); - - $('#add_application_token_btn').on('click', function (_event) { - $('#add_application_token_form').toggle(400, 'swing', function () { - if ($('#add_application_token_form').is(':visible')) { - $('#add_application_token_btn i').addClass('fa-minus-circle'); - $('#add_application_token_btn i').removeClass('fa-plus-circle'); - $('#application_token_application').val(''); - $('#application_token_application').focus(); - } else { - $('#add_application_token_btn i').removeClass('fa-minus-circle'); - $('#add_application_token_btn i').addClass('fa-plus-circle'); - } - layout_resizer(); - }); - }); -}); diff --git a/app/assets/javascripts/base/component.js b/app/assets/javascripts/base/component.js new file mode 100644 index 000000000..3815306ae --- /dev/null +++ b/app/assets/javascripts/base/component.js @@ -0,0 +1,27 @@ +class BaseComponent { + constructor(el) { + this.$el = el; + + if (this.elements) { + this.elements(); + } + + if (this.events) { + this.events(); + } + + if (this.beforeMount) { + this.beforeMount(); + } + + if (this.mount) { + this.mount(); + } + + if (this.mounted) { + this.mounted(); + } + } +} + +export default BaseComponent; diff --git a/app/assets/javascripts/modules/users/components/application-token-panel.js b/app/assets/javascripts/modules/users/components/application-token-panel.js new file mode 100644 index 000000000..b76d2aa95 --- /dev/null +++ b/app/assets/javascripts/modules/users/components/application-token-panel.js @@ -0,0 +1,41 @@ +import BaseComponent from '~/base/component'; + +const TOGGLE_LINK = '#add_application_token_btn'; +const TOGGLE_LINK_ICON = `${TOGGLE_LINK} i`; +const APP_TOKEN_FORM = '#add_application_token_form'; +const APP_TOKEN_FIELD = '#application_token_application'; + +class ApplicationTokenPanel extends BaseComponent { + elements() { + this.$toggle = this.$el.find(TOGGLE_LINK); + this.$toggleIcon = this.$el.find(TOGGLE_LINK_ICON); + this.$form = this.$el.find(APP_TOKEN_FORM); + this.$token = this.$el.find(APP_TOKEN_FIELD); + } + + events() { + this.$el.on('click', TOGGLE_LINK, e => this.onClick(e)); + } + + onClick() { + this.$form.toggle(400, 'swing', () => { + const visible = this.$form.is(':visible'); + + if (visible) { + this.clearFields(); + } + + this.$toggleIcon.toggleClass('fa-minus-circle', visible); + this.$toggleIcon.toggleClass('fa-plus-circle', !visible); + + layout_resizer(); + }); + } + + clearFields() { + this.$token.val(''); + this.$token.focus(); + } +} + +export default ApplicationTokenPanel; diff --git a/app/assets/javascripts/modules/users/components/password-form.js b/app/assets/javascripts/modules/users/components/password-form.js new file mode 100644 index 000000000..ad6bad802 --- /dev/null +++ b/app/assets/javascripts/modules/users/components/password-form.js @@ -0,0 +1,40 @@ +import BaseComponent from '~/base/component'; + +const CURRENT_PASSWORD_FIELD = '#user_current_password'; +const NEW_PASSWORD_FIELD = '#user_password'; +const NEW_CONFIRMATION_PASSWORD_FIELD = '#user_password_confirmation'; +const SUBMIT_BUTTON = 'input[type=submit]'; + +class UsersPasswordForm extends BaseComponent { + elements() { + this.$currentPassword = this.$el.find(CURRENT_PASSWORD_FIELD); + this.$newPassword = this.$el.find(NEW_PASSWORD_FIELD); + this.$newPasswordConfirmation = this.$el.find(NEW_CONFIRMATION_PASSWORD_FIELD); + this.$submit = this.$el.find(SUBMIT_BUTTON); + } + + events() { + this.$el.on('keyup', CURRENT_PASSWORD_FIELD, e => this.onKeyup(e)); + this.$el.on('keyup', NEW_PASSWORD_FIELD, e => this.onKeyup(e)); + this.$el.on('keyup', NEW_CONFIRMATION_PASSWORD_FIELD, e => this.onKeyup(e)); + } + + onKeyup() { + const currentPassword = this.$currentPassword.val(); + const newPassword = this.$newPassword.val(); + const newPasswordConfirmation = this.$newPasswordConfirmation.val(); + + const currentPasswordInvalid = !currentPassword; + const newPasswordInvalid = !newPassword; + const newPasswordConfirmationInvalid = !newPasswordConfirmation || + newPassword !== newPasswordConfirmation; + + if (currentPasswordInvalid || newPasswordInvalid || newPasswordConfirmationInvalid) { + this.$submit.attr('disabled', 'disabled'); + } else { + this.$submit.removeAttr('disabled'); + } + } +} + +export default UsersPasswordForm; diff --git a/app/assets/javascripts/modules/users/components/profile-form.js b/app/assets/javascripts/modules/users/components/profile-form.js new file mode 100644 index 000000000..0f0d4ab14 --- /dev/null +++ b/app/assets/javascripts/modules/users/components/profile-form.js @@ -0,0 +1,40 @@ +import BaseComponent from '~/base/component'; + +const EMAIL_FIELD = '#user_email'; +const DISPLAY_NAME_FIELD = '#user_display_name'; +const SUBMIT_BUTTON = 'input[type=submit]'; + +class UsersProfileForm extends BaseComponent { + elements() { + this.$email = this.$el.find(EMAIL_FIELD); + this.$displayName = this.$el.find(DISPLAY_NAME_FIELD); + this.$submit = this.$el.find(SUBMIT_BUTTON); + } + + events() { + this.$el.on('keyup', EMAIL_FIELD, e => this.onKeyup(e)); + this.$el.on('keyup', DISPLAY_NAME_FIELD, e => this.onKeyup(e)); + } + + onKeyup() { + const email = this.$email.val(); + const displayName = this.$displayName.val(); + + const emailInvalid = !email || email === this.originalEmail; + const displayNameInvalid = this.$displayName[0] && + (!displayName || displayName === this.originalDisplayName); + + if (emailInvalid || displayNameInvalid) { + this.$submit.attr('disabled', 'disabled'); + } else { + this.$submit.removeAttr('disabled'); + } + } + + mounted() { + this.originalEmail = this.$email.val(); + this.originalDisplayName = this.$displayName.val(); + } +} + +export default UsersProfileForm; diff --git a/app/assets/javascripts/modules/users/index.js b/app/assets/javascripts/modules/users/index.js new file mode 100644 index 000000000..3bb946d6d --- /dev/null +++ b/app/assets/javascripts/modules/users/index.js @@ -0,0 +1,27 @@ +import UsersEditPage from './pages/edit'; +import UsersSignUpPage from './pages/sign-up'; +import UsersSignInPage from './pages/sign-in'; + +const USERS_EDIT_ROUTE = 'auth/registrations/edit'; +const USERS_SIGN_IN_ROUTE = 'auth/sessions/new'; +const USERS_SIGN_UP_ROUTE = 'auth/registrations/new'; + +$(() => { + const $body = $('body'); + const route = $body.data('route'); + + if (route === USERS_EDIT_ROUTE) { + // eslint-disable-next-line + new UsersEditPage($body); + } + + if (route === USERS_SIGN_UP_ROUTE) { + // eslint-disable-next-line + new UsersSignUpPage($body); + } + + if (route === USERS_SIGN_IN_ROUTE) { + // eslint-disable-next-line + new UsersSignInPage($body); + } +}); diff --git a/app/assets/javascripts/modules/users/pages/edit.js b/app/assets/javascripts/modules/users/pages/edit.js new file mode 100644 index 000000000..fd4852ace --- /dev/null +++ b/app/assets/javascripts/modules/users/pages/edit.js @@ -0,0 +1,25 @@ +import BaseComponent from '~/base/component'; + +import ProfileForm from '../components/profile-form'; +import PasswordForm from '../components/password-form'; +import ApplicationTokenPanel from '../components/application-token-panel'; + +const PROFILE_FORM = 'form.profile'; +const PASSWORD_FORM = 'form.password'; +const APP_TOKEN_PANEL = '.app-token-wrapper'; + +class UsersEditPage extends BaseComponent { + elements() { + this.$profileForm = this.$el.find(PROFILE_FORM); + this.$passwordForm = this.$el.find(PASSWORD_FORM); + this.$appTokenPanel = this.$el.find(APP_TOKEN_PANEL); + } + + mount() { + this.profileForm = new ProfileForm(this.$profileForm); + this.passwordForm = new PasswordForm(this.$passwordForm); + this.appTokenPanel = new ApplicationTokenPanel(this.$appTokenPanel); + } +} + +export default UsersEditPage; diff --git a/app/assets/javascripts/modules/users/pages/sign-in.js b/app/assets/javascripts/modules/users/pages/sign-in.js new file mode 100644 index 000000000..51c374b13 --- /dev/null +++ b/app/assets/javascripts/modules/users/pages/sign-in.js @@ -0,0 +1,11 @@ +import BaseComponent from '~/base/component'; + +import { fadeIn } from '~/utils/effects'; + +class UsersSignInPage extends BaseComponent { + mount() { + fadeIn(this.$el); + } +} + +export default UsersSignInPage; diff --git a/app/assets/javascripts/modules/users/pages/sign-up.js b/app/assets/javascripts/modules/users/pages/sign-up.js new file mode 100644 index 000000000..8531de905 --- /dev/null +++ b/app/assets/javascripts/modules/users/pages/sign-up.js @@ -0,0 +1,11 @@ +import BaseComponent from '~/base/component'; + +import { fadeIn } from '~/utils/effects'; + +class UsersSignUpPage extends BaseComponent { + mount() { + fadeIn(this.$el); + } +} + +export default UsersSignUpPage; diff --git a/app/assets/javascripts/namespaces.js b/app/assets/javascripts/namespaces.js index 035c9634f..b2de04237 100644 --- a/app/assets/javascripts/namespaces.js +++ b/app/assets/javascripts/namespaces.js @@ -1,8 +1,3 @@ -/* global layout_resizer, set_typeahead, open_close_icon */ - -//= require includes/set_typehead -//= require includes/open_close_icon - jQuery(function ($) { $('#edit_namespace').on('click', function (_event) { set_typeahead('/teams/typeahead/%QUERY'); diff --git a/app/assets/javascripts/repositories.js b/app/assets/javascripts/repositories.js index 9a2ec3b17..032ffa708 100644 --- a/app/assets/javascripts/repositories.js +++ b/app/assets/javascripts/repositories.js @@ -1,5 +1,3 @@ -/* global layout_resizer */ - jQuery(function ($) { // Shows and hides the comment form $('#write_comment_repository_btn').unbind('click').on('click', function (_e) { diff --git a/app/assets/javascripts/teams.js b/app/assets/javascripts/teams.js index de89c8ac1..9adc33d4e 100644 --- a/app/assets/javascripts/teams.js +++ b/app/assets/javascripts/teams.js @@ -1,7 +1,3 @@ -/* global layout_resizer, set_typeahead, open_close_icon */ - -//= require namespaces - jQuery(function ($) { $('#add_team_user_btn').on('click', function (_event) { var team_id; diff --git a/app/assets/javascripts/utils/effects.js b/app/assets/javascripts/utils/effects.js new file mode 100644 index 000000000..b9d86249e --- /dev/null +++ b/app/assets/javascripts/utils/effects.js @@ -0,0 +1,12 @@ +// after jquery was upgraded this effect was conflicting +// with lifeitup functions (probably layout_resizer) +// so setTimeout was the workaround I found to solve the error +export const fadeIn = function ($el) { + setTimeout(() => { + $el.hide().fadeIn(1000); + }, 0); +}; + +export default { + fadeIn, +}; diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 17bb4018e..e7199bbe1 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,6 +1,18 @@ module ApplicationHelper include ActivitiesHelper + ACTION_ALIASES = { + "update" => "edit", + "create" => "new" + }.freeze + + def js_route + action_name = ACTION_ALIASES[controller.action_name] || controller.action_name + controller_name = controller.class.name.underscore.gsub("_controller", "") + + "#{controller_name}/#{action_name}" + end + # Render the user profile picture depending on the gravatar configuration. def user_image_tag(owner) email = owner.nil? ? nil : owner.email diff --git a/app/views/devise/registrations/edit.html.slim b/app/views/devise/registrations/edit.html.slim index 4a3688137..c9c26913a 100644 --- a/app/views/devise/registrations/edit.html.slim +++ b/app/views/devise/registrations/edit.html.slim @@ -27,44 +27,45 @@ .actions = f.submit('Update', class: 'btn btn-primary', disabled: true) - #add_application_token_form.collapse - = form_for :application_token, url: application_tokens_path, remote: true, html: {id: 'new-application-token-form', class: 'form-horizontal', role: 'form'} do |f| - .form-group - = f.label :application, {class: 'control-label col-md-2'} - .col-md-7 - = f.text_field(:application, class: 'form-control', required: true, placeholder: "Name") - .form-group - .col-md-offset-2.col-md-7 - = f.submit('Create', class: 'btn btn-primary') + .app-token-wrapper + #add_application_token_form.collapse + = form_for :application_token, url: application_tokens_path, remote: true, html: {id: 'new-application-token-form', class: 'form-horizontal', role: 'form'} do |f| + .form-group + = f.label :application, {class: 'control-label col-md-2'} + .col-md-7 + = f.text_field(:application, class: 'form-control', required: true, placeholder: "Name") + .form-group + .col-md-offset-2.col-md-7 + = f.submit('Create', class: 'btn btn-primary') - .panel.panel-default - .panel-heading - .row - .col-sm-6 - h5 - ' Application tokens - .col-sm-6.text-right - - if current_user.application_tokens.count >= User::APPLICATION_TOKENS_MAX - a#add_application_token_btn.btn.btn-xs.btn-link.js-toggle-button[disabled="disabled" role="button"] - i.fa.fa-plus-circle - | Create new token - - else - a#add_application_token_btn.btn.btn-xs.btn-link.js-toggle-button[role="button"] - i.fa.fa-plus-circle - | Create new token - .panel-body - .table-responsive - table.table.table-striped.table-hover - colgroup - col.col-90 - col.col-10 - thead - tr - th Application - th Remove - tbody#application_tokens - - current_user.application_tokens.each do |token| - = render partial: 'application_tokens/application_token', locals: {application_token: token} + .panel.panel-default + .panel-heading + .row + .col-sm-6 + h5 + ' Application tokens + .col-sm-6.text-right + - if current_user.application_tokens.count >= User::APPLICATION_TOKENS_MAX + a#add_application_token_btn.btn.btn-xs.btn-link.js-toggle-button[disabled="disabled" role="button"] + i.fa.fa-plus-circle + | Create new token + - else + a#add_application_token_btn.btn.btn-xs.btn-link.js-toggle-button[role="button"] + i.fa.fa-plus-circle + | Create new token + .panel-body + .table-responsive + table.table.table-striped.table-hover + colgroup + col.col-90 + col.col-10 + thead + tr + th Application + th Remove + tbody#application_tokens + - current_user.application_tokens.each do |token| + = render partial: 'application_tokens/application_token', locals: {application_token: token} - if current_user.email? - unless current_user.admin? && @admin_count == 1 diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index 745408668..8735faa30 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -29,7 +29,7 @@ html meta content="/favicon/browserconfig.xml" name="msapplication-config" meta content="#205683" name="theme-color" - body + body data-route="#{js_route}" header = render 'shared/header' .container-fluid diff --git a/app/views/layouts/authentication.html.slim b/app/views/layouts/authentication.html.slim index 53fdad230..7b5d607a7 100644 --- a/app/views/layouts/authentication.html.slim +++ b/app/views/layouts/authentication.html.slim @@ -28,6 +28,6 @@ html meta content="/favicon/mstile-144x144.png" name="msapplication-TileImage" meta content="/favicon/browserconfig.xml" name="msapplication-config" meta content="#205683" name="theme-color" - body.login + body.login data-route="#{js_route}" .container-fluid = yield diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index b851f2746..8f166b483 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -105,4 +105,25 @@ def time_tag(first, second, _args) expect(show_first_user_alert?).to be_falsey end end + + describe "#js_route" do + # controller.class === ActionView::TestCase::TestController + it "should return controller_name/action_name format" do + allow(controller).to receive(:action_name) { "action" } + + expect(js_route).to eq("action_view/test_case/test/action") + end + + it "should alias update as edit action name" do + allow(controller).to receive(:action_name) { "update" } + + expect(js_route).to eq("action_view/test_case/test/edit") + end + + it "should alias create as new action name" do + allow(controller).to receive(:action_name) { "create" } + + expect(js_route).to eq("action_view/test_case/test/new") + end + end end diff --git a/vendor/assets/javascripts/lifeitup_layout.js b/vendor/assets/javascripts/lifeitup_layout.js index 153089619..bc64de09d 100644 --- a/vendor/assets/javascripts/lifeitup_layout.js +++ b/vendor/assets/javascripts/lifeitup_layout.js @@ -1,130 +1,130 @@ -// to render the layout correctly in every browser/screen - -window.$ = window.jQuery; -var alreadyResizing = false; - -$(window).on("load", function() { - - layout_resizer (); - add_view_image_icon (); - resize_view_image_icon (); - -}); - -$(window).on("resize", function() { - - layout_resizer (); - resize_view_image_icon (); - -}); - -$(document).bind("DOMSubtreeModified", function() { - if (!alreadyResizing) { - layout_resizer (); - } -}); - -// triger the function to resize and to get the images size when a panel has been displayed -$(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function () { - layout_resizer(); - resize_view_image_icon(); -}) - - -function layout_resizer () { - alreadyResizing = true; - - var screenHeight = $(window).height(); - var headerHeight = $("header").outerHeight(); - var footerHeight = $("footer").outerHeight(); - var asideHeight = $("aside ul").outerHeight(); - var sectionHeight = $("section").outerHeight(); - - if ( ( headerHeight + footerHeight + asideHeight ) > screenHeight && asideHeight > sectionHeight ) { - - $(".container-fluid").css({ - height : asideHeight + "px" - }); - - } else if ( ( headerHeight + footerHeight + sectionHeight ) > screenHeight && asideHeight < sectionHeight) { - - $(".container-fluid").css({ - height : sectionHeight + "px" - }); - - } else { - - $(".container-fluid").css({ - height : screenHeight - headerHeight - footerHeight + "px" - }); - - } - - alreadyResizing = false; -} -window.layout_resizer = layout_resizer; - -// BOOTSTRAP INITS -// init popovers - -$(function () { - $('body').popover({ - selector: '[data-toggle="popover"]', - trigger: 'focus' - }) - // to destroy the popovers that are hidden - $('[data-toggle="popover"]').on('hidden.bs.popover', function () { - var popover = $('.popover').not('.in'); - if (popover) { - popover.remove(); - } - }) -}) - -// init tooltip - -$(function () { - $('[data-toggle="tooltip"]').tooltip() -}) - - -// View image -function add_view_image_icon () { - $(".view-img-link").append("
") -} -window.add_view_image_icon = add_view_image_icon; - -function resize_view_image_icon () { - $(".view-img-link").each(function() { - var imageHeight = $(this).children("img").height() - var imageWitdh = $(this).children("img").width() - var paddingVertical = (imageHeight - 44) / 2 - $(this).children(".view-img").css({ - height : imageHeight, - width : imageWitdh, - "padding-top" : paddingVertical - }) - }) - -} -window.resize_view_image_icon = resize_view_image_icon; - - -// Functions for the mobile version -$(document).on("click", '#open_main_menu', open_mobile_menu); -var menu_open = false -function open_mobile_menu () { - if (menu_open) { - $('aside').css({'margin-left': '-250px'}); - menu_open = false; - } else { - $('aside').css({'margin-left': '0px'}); - menu_open = true - } -} -window.open_mobile_menu = open_mobile_menu; - -// Hide alert box instead of closing it -$(document).on('click', '.alert-hide', function() { - $(this).parent().parent().fadeOut(); -}); +// to render the layout correctly in every browser/screen + +window.$ = window.jQuery; +var alreadyResizing = false; + +$(window).on("load", function() { + + layout_resizer (); + add_view_image_icon (); + resize_view_image_icon (); + +}); + +$(window).on("resize", function() { + + layout_resizer (); + resize_view_image_icon (); + +}); + +$(document).bind("DOMSubtreeModified", function() { + if (!alreadyResizing) { + layout_resizer (); + } +}); + +// triger the function to resize and to get the images size when a panel has been displayed +$(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function () { + layout_resizer(); + resize_view_image_icon(); +}) + + +function layout_resizer () { + alreadyResizing = true; + + var screenHeight = $(window).height(); + var headerHeight = $("header").outerHeight(); + var footerHeight = $("footer").outerHeight(); + var asideHeight = $("aside ul").outerHeight(); + var sectionHeight = $("section").outerHeight(); + + if ( ( headerHeight + footerHeight + asideHeight ) > screenHeight && asideHeight > sectionHeight ) { + + $(".container-fluid").css({ + height : asideHeight + "px" + }); + + } else if ( ( headerHeight + footerHeight + sectionHeight ) > screenHeight && asideHeight < sectionHeight) { + + $(".container-fluid").css({ + height : sectionHeight + "px" + }); + + } else { + + $(".container-fluid").css({ + height : screenHeight - headerHeight - footerHeight + "px" + }); + + } + + alreadyResizing = false; +} +window.layout_resizer = layout_resizer; + +// BOOTSTRAP INITS +// init popovers + +$(function () { + $('body').popover({ + selector: '[data-toggle="popover"]', + trigger: 'focus' + }) + // to destroy the popovers that are hidden + $('[data-toggle="popover"]').on('hidden.bs.popover', function () { + var popover = $('.popover').not('.in'); + if (popover) { + popover.remove(); + } + }) +}) + +// init tooltip + +$(function () { + $('[data-toggle="tooltip"]').tooltip() +}) + + +// View image +function add_view_image_icon () { + $(".view-img-link").append("
") +} +window.add_view_image_icon = add_view_image_icon; + +function resize_view_image_icon () { + $(".view-img-link").each(function() { + var imageHeight = $(this).children("img").height() + var imageWitdh = $(this).children("img").width() + var paddingVertical = (imageHeight - 44) / 2 + $(this).children(".view-img").css({ + height : imageHeight, + width : imageWitdh, + "padding-top" : paddingVertical + }) + }) + +} +window.resize_view_image_icon = resize_view_image_icon; + + +// Functions for the mobile version +$(document).on("click", '#open_main_menu', open_mobile_menu); +var menu_open = false +function open_mobile_menu () { + if (menu_open) { + $('aside').css({'margin-left': '-250px'}); + menu_open = false; + } else { + $('aside').css({'margin-left': '0px'}); + menu_open = true + } +} +window.open_mobile_menu = open_mobile_menu; + +// Hide alert box instead of closing it +$(document).on('click', '.alert-hide', function() { + $(this).parent().parent().fadeOut(); +});