diff options
author | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2017-07-26 14:54:45 +0200 |
---|---|---|
committer | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2017-07-26 14:54:45 +0200 |
commit | 79a7f7b6e59fa1225c440547796331caedabeaab (patch) | |
tree | f002dd7d26c38f358e626e269543628e06c4cb4b /app/assets/javascripts | |
parent | 7d6538f2e2a6f1b0808a77e347a9083295b17c8c (diff) | |
parent | 5f35901a01ff822ba1e637251d9726a41e73ed17 (diff) | |
download | gitlab-ce-79a7f7b6e59fa1225c440547796331caedabeaab.tar.gz |
Merge branch 'master' into backstage/gb/migrate-stages-statuses
* master: (110 commits)
Add missing colon
Fix project wiki web_url spec
Resolve "Memory usage notice doesn't link anywhere"
Docs new topic "user/index"
Implement GRPC call to RepositoryService
Pending delete projects should not show in deploy keys
Remove outdated ~Frontend label in CONTRIBUTING.md
Fixes 500 error caused by pending delete projects in admin dashboard
Add lower path index to redirect_routes
Remove project_key from the Jira configuration
Update CHANGELOG.md for 9.4.1
Enable gitaly_post_upload_pack by default
Add `api` prefix as a top level route in the spec.
Move relative_path to the element that is being clicked
Bumps Gitlab Omniauth LDAP version
Add directives to Vue component ordering
synchronize ukrainian translation in zanata again
v3 API is unsupported after 9.5, but may not be removed
Fix vertical alignment in firefox and safari for pipeline mini graph
Adds link_to_gfm method instrumentation
...
Conflicts:
db/schema.rb
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r-- | app/assets/javascripts/copy_as_gfm.js | 10 | ||||
-rw-r--r-- | app/assets/javascripts/how_to_merge.js | 12 | ||||
-rw-r--r-- | app/assets/javascripts/lazy_loader.js | 76 | ||||
-rw-r--r-- | app/assets/javascripts/main.js | 14 | ||||
-rw-r--r-- | app/assets/javascripts/merge_conflicts/merge_conflict_store.js | 2 | ||||
-rw-r--r-- | app/assets/javascripts/star.js | 6 | ||||
-rw-r--r-- | app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js | 11 |
8 files changed, 120 insertions, 14 deletions
diff --git a/app/assets/javascripts/copy_as_gfm.js b/app/assets/javascripts/copy_as_gfm.js index ba9d9a3e1f7..54257531284 100644 --- a/app/assets/javascripts/copy_as_gfm.js +++ b/app/assets/javascripts/copy_as_gfm.js @@ -1,6 +1,7 @@ /* eslint-disable class-methods-use-this, object-shorthand, no-unused-vars, no-use-before-define, no-new, max-len, no-restricted-syntax, guard-for-in, no-continue */ import './lib/utils/common_utils'; +import { placeholderImage } from './lazy_loader'; const gfmRules = { // The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert @@ -56,6 +57,11 @@ const gfmRules = { return text; }, }, + ImageLazyLoadFilter: { + 'img'(el, text) { + return `![${el.getAttribute('alt')}](${el.getAttribute('src')})`; + }, + }, VideoLinkFilter: { '.video-container'(el) { const videoEl = el.querySelector('video'); @@ -163,7 +169,9 @@ const gfmRules = { return text.trim().split('\n').map(s => `> ${s}`.trim()).join('\n'); }, 'img'(el) { - return `![${el.getAttribute('alt')}](${el.getAttribute('src')})`; + const imageSrc = el.src; + const imageUrl = imageSrc && imageSrc !== placeholderImage ? imageSrc : (el.dataset.src || ''); + return `![${el.getAttribute('alt')}](${imageUrl})`; }, 'a.anchor'(el, text) { // Don't render a Markdown link for the anchor link inside a heading diff --git a/app/assets/javascripts/how_to_merge.js b/app/assets/javascripts/how_to_merge.js new file mode 100644 index 00000000000..f739db751a6 --- /dev/null +++ b/app/assets/javascripts/how_to_merge.js @@ -0,0 +1,12 @@ +document.addEventListener('DOMContentLoaded', () => { + const modal = $('#modal_merge_info').modal({ + modal: true, + show: false, + }); + $('.how_to_merge_link').bind('click', () => { + modal.show(); + }); + $('.modal-header .close').bind('click', () => { + modal.hide(); + }); +}); diff --git a/app/assets/javascripts/lazy_loader.js b/app/assets/javascripts/lazy_loader.js new file mode 100644 index 00000000000..3d64b121fa7 --- /dev/null +++ b/app/assets/javascripts/lazy_loader.js @@ -0,0 +1,76 @@ +/* eslint-disable one-export, one-var, one-var-declaration-per-line */ + +import _ from 'underscore'; + +export const placeholderImage = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='; +const SCROLL_THRESHOLD = 300; + +export default class LazyLoader { + constructor(options = {}) { + this.lazyImages = []; + this.observerNode = options.observerNode || '#content-body'; + + const throttledScrollCheck = _.throttle(() => this.scrollCheck(), 300); + const debouncedElementsInView = _.debounce(() => this.checkElementsInView(), 300); + + window.addEventListener('scroll', throttledScrollCheck); + window.addEventListener('resize', debouncedElementsInView); + + const scrollContainer = options.scrollContainer || window; + scrollContainer.addEventListener('load', () => this.loadCheck()); + } + searchLazyImages() { + this.lazyImages = [].slice.call(document.querySelectorAll('.lazy')); + this.checkElementsInView(); + } + startContentObserver() { + const contentNode = document.querySelector(this.observerNode) || document.querySelector('body'); + + if (contentNode) { + const observer = new MutationObserver(() => this.searchLazyImages()); + + observer.observe(contentNode, { + childList: true, + subtree: true, + }); + } + } + loadCheck() { + this.searchLazyImages(); + this.startContentObserver(); + } + scrollCheck() { + requestAnimationFrame(() => this.checkElementsInView()); + } + checkElementsInView() { + const scrollTop = pageYOffset; + const visHeight = scrollTop + innerHeight + SCROLL_THRESHOLD; + let imgBoundRect, imgTop, imgBound; + + // Loading Images which are in the current viewport or close to them + this.lazyImages = this.lazyImages.filter((selectedImage) => { + if (selectedImage.getAttribute('data-src')) { + imgBoundRect = selectedImage.getBoundingClientRect(); + + imgTop = scrollTop + imgBoundRect.top; + imgBound = imgTop + imgBoundRect.height; + + if (scrollTop < imgBound && visHeight > imgTop) { + LazyLoader.loadImage(selectedImage); + return false; + } + + return true; + } + return false; + }); + } + static loadImage(img) { + if (img.getAttribute('data-src')) { + img.setAttribute('src', img.getAttribute('data-src')); + img.removeAttribute('data-src'); + img.classList.remove('lazy'); + img.classList.add('js-lazy-loaded'); + } + } +} diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 26c67fb721c..e96d51de838 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -109,6 +109,7 @@ import './label_manager'; import './labels'; import './labels_select'; import './layout_nav'; +import LazyLoader from './lazy_loader'; import './line_highlighter'; import './logo'; import './member_expiration_date'; @@ -166,6 +167,11 @@ window.addEventListener('load', function onLoad() { gl.utils.handleLocationHash(); }, false); +gl.lazyLoader = new LazyLoader({ + scrollContainer: window, + observerNode: '#content-body' +}); + $(function () { var $body = $('body'); var $document = $(document); @@ -284,13 +290,7 @@ $(function () { return $container.remove(); // Commit show suppressed diff }); - $('.navbar-toggle').on('click', function () { - $('.header-content .title, .header-content .navbar-sub-nav').toggle(); - $('.header-content .header-logo').toggle(); - $('.header-content .navbar-collapse').toggle(); - $('.js-navbar-toggle-left, .js-navbar-toggle-right, .title-container').toggle(); - return $('.navbar-toggle').toggleClass('active'); - }); + $('.navbar-toggle').on('click', () => $('.header-content').toggleClass('menu-expanded')); // Show/hide comments on diff $body.on('click', '.js-toggle-diff-comments', function (e) { var $this = $(this); diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js index c4e379a4a0b..8be7314ded8 100644 --- a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js +++ b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js @@ -175,7 +175,7 @@ import Cookies from 'js-cookie'; getConflictsCountText() { const count = this.getConflictsCount(); - const text = count ? 'conflicts' : 'conflict'; + const text = count > 1 ? 'conflicts' : 'conflict'; return `${count} ${text}`; }, diff --git a/app/assets/javascripts/star.js b/app/assets/javascripts/star.js index 6d38124f1c1..3a06b477d7c 100644 --- a/app/assets/javascripts/star.js +++ b/app/assets/javascripts/star.js @@ -1,6 +1,8 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-unused-vars, one-var, no-var, one-var-declaration-per-line, prefer-arrow-callback, no-new, max-len */ /* global Flash */ +import { __, s__ } from './locale'; + export default class Star { constructor() { $('.project-home-panel .toggle-star').on('ajax:success', function(e, data, status, xhr) { @@ -11,10 +13,10 @@ export default class Star { toggleStar = function(isStarred) { $this.parent().find('.star-count').text(data.star_count); if (isStarred) { - $starSpan.removeClass('starred').text('Star'); + $starSpan.removeClass('starred').text(s__('StarProject|Star')); $starIcon.removeClass('fa-star').addClass('fa-star-o'); } else { - $starSpan.addClass('starred').text('Unstar'); + $starSpan.addClass('starred').text(__('Unstar')); $starIcon.removeClass('fa-star-o').addClass('fa-star'); } }; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js index e8e22ad93a5..744a1cd24fa 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js @@ -108,7 +108,8 @@ export default { </div> <mr-widget-memory-usage v-if="deployment.metrics_url" - :metricsUrl="deployment.metrics_url" + :metrics-url="deployment.metrics_url" + :metrics-monitoring-url="deployment.metrics_monitoring_url" /> </div> </div> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js index 76cb71b6c12..534e2a88eff 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js @@ -7,7 +7,14 @@ import MRWidgetService from '../services/mr_widget_service'; export default { name: 'MemoryUsage', props: { - metricsUrl: { type: String, required: true }, + metricsUrl: { + type: String, + required: true, + }, + metricsMonitoringUrl: { + type: String, + required: true, + }, }, data() { return { @@ -124,7 +131,7 @@ export default { <p v-if="shouldShowMemoryGraph" class="usage-info js-usage-info"> - Memory usage <b>{{memoryChangeType}}</b> from {{memoryFrom}}MB to {{memoryTo}}MB + <a :href="metricsMonitoringUrl">Memory</a> usage <b>{{memoryChangeType}}</b> from {{memoryFrom}}MB to {{memoryTo}}MB </p> <p v-if="shouldShowLoadFailure" |