Commit d3affe8b authored by Jacob Vosmaer's avatar Jacob Vosmaer

Merge remote-tracking branch 'origin/master' into lazy-blobs

parents e08aa3df 6cffcb05
...@@ -4,6 +4,7 @@ v 8.5.0 (unreleased) ...@@ -4,6 +4,7 @@ v 8.5.0 (unreleased)
- Ensure rake tasks that don't need a DB connection can be run without one - Ensure rake tasks that don't need a DB connection can be run without one
- Add "visibility" flag to GET /projects api endpoint - Add "visibility" flag to GET /projects api endpoint
- Ignore binary files in code search to prevent Error 500 (Stan Hu) - Ignore binary files in code search to prevent Error 500 (Stan Hu)
- Render sanitized SVG images (Stan Hu)
- Upgrade gitlab_git to 7.2.23 to fix commit message mentions in first branch push - Upgrade gitlab_git to 7.2.23 to fix commit message mentions in first branch push
- New UI for pagination - New UI for pagination
- Don't prevent sign out when 2FA enforcement is enabled and user hasn't yet - Don't prevent sign out when 2FA enforcement is enabled and user hasn't yet
...@@ -14,7 +15,9 @@ v 8.5.0 (unreleased) ...@@ -14,7 +15,9 @@ v 8.5.0 (unreleased)
- Display 404 error on group not found - Display 404 error on group not found
- Track project import failure - Track project import failure
- Fix visibility level text in admin area (Zeger-Jan van de Weg) - Fix visibility level text in admin area (Zeger-Jan van de Weg)
- Warn admin during OAuth of granting admin rights (Zeger-Jan van de Weg)
- Update the ExternalIssue regex pattern (Blake Hitchcock) - Update the ExternalIssue regex pattern (Blake Hitchcock)
- Optimized performance of finding issues to be closed by a merge request
- Revert "Add IP check against DNSBLs at account sign-up" - Revert "Add IP check against DNSBLs at account sign-up"
- Deprecate API "merge_request/:merge_request_id/comments". Use "merge_requests/:merge_request_id/notes" instead - Deprecate API "merge_request/:merge_request_id/comments". Use "merge_requests/:merge_request_id/notes" instead
- Deprecate API "merge_request/:merge_request_id/...". Use "merge_requests/:merge_request_id/..." instead - Deprecate API "merge_request/:merge_request_id/...". Use "merge_requests/:merge_request_id/..." instead
...@@ -46,7 +49,6 @@ v 8.4.1 ...@@ -46,7 +49,6 @@ v 8.4.1
and Nokogiri (1.6.7.2) and Nokogiri (1.6.7.2)
- Fix redirect loop during import - Fix redirect loop during import
- Fix diff highlighting for all syntax themes - Fix diff highlighting for all syntax themes
- Warn admin during OAuth of granting admin rights (Zeger-Jan van de Weg)
- Delete project and associations in a background worker - Delete project and associations in a background worker
v 8.4.0 v 8.4.0
......
...@@ -177,6 +177,26 @@ is probably 1, adding a new Git Hook maybe 4 or 5, big features 7-9. ...@@ -177,6 +177,26 @@ is probably 1, adding a new Git Hook maybe 4 or 5, big features 7-9.
issues or chunks. You can simply not set the weight of a parent issue and set issues or chunks. You can simply not set the weight of a parent issue and set
weights to children issues. weights to children issues.
### Regression issues
Every monthly release has a corresponding issue on the CE issue tracker to keep
track of functionality broken by that release and any fixes that need to be
included in a patch release (see [8.3 Regressions] as an example).
As outlined in the issue description, the intended workflow is to post one note
with a reference to an issue describing the regression, and then to update that
note with a reference to the merge request that fixes it as it becomes available.
If you're a contributor who doesn't have the required permissions to update
other users' notes, please post a new note with a reference to both the issue
and the merge request.
The release manager will [update the notes] in the regression issue as fixes are
addressed.
[8.3 Regressions]: https://gitlab.com/gitlab-org/gitlab-ce/issues/4127
[update the notes]: https://gitlab.com/gitlab-org/release-tools/blob/master/doc/pro-tips.md#update-the-regression-issue
## Merge requests ## Merge requests
We welcome merge requests with fixes and improvements to GitLab code, tests, We welcome merge requests with fixes and improvements to GitLab code, tests,
......
...@@ -179,6 +179,9 @@ gem "underscore-rails", "~> 1.8.0" ...@@ -179,6 +179,9 @@ gem "underscore-rails", "~> 1.8.0"
gem "sanitize", '~> 2.0' gem "sanitize", '~> 2.0'
gem 'babosa', '~> 1.0.2' gem 'babosa', '~> 1.0.2'
# Sanitizes SVG input
gem "loofah", "~> 2.0.3"
# Protect against bruteforcing # Protect against bruteforcing
gem "rack-attack", '~> 4.3.1' gem "rack-attack", '~> 4.3.1'
......
...@@ -953,6 +953,7 @@ DEPENDENCIES ...@@ -953,6 +953,7 @@ DEPENDENCIES
jquery-ui-rails (~> 5.0.0) jquery-ui-rails (~> 5.0.0)
kaminari (~> 0.16.3) kaminari (~> 0.16.3)
letter_opener (~> 1.1.2) letter_opener (~> 1.1.2)
loofah (~> 2.0.3)
mail_room (~> 0.6.1) mail_room (~> 0.6.1)
method_source (~> 0.8) method_source (~> 0.8)
minitest (~> 5.7.0) minitest (~> 5.7.0)
......
#= require jquery.ba-resize
#= require autosize #= require autosize
$ -> $ ->
autosize($('.js-autosize')) $fields = $('.js-autosize')
$fields.on 'autosize:resized', ->
$field = $(@)
$field.data('height', $field.outerHeight())
$fields.on 'resize.autosize', ->
$field = $(@)
if $field.data('height') != $field.outerHeight()
$field.data('height', $field.outerHeight())
autosize.destroy($field)
$field.css('max-height', window.outerHeight)
autosize($fields)
autosize.update($fields)
$fields.css('resize', 'vertical')
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
background: #FFF; background: #FFF;
border: 1px solid #ddd; border: 1px solid #ddd;
min-height: 140px; min-height: 140px;
max-height: 430px; max-height: 500px;
padding: 5px; padding: 5px;
box-shadow: none; box-shadow: none;
width: 100%; width: 100%;
......
...@@ -147,7 +147,7 @@ ...@@ -147,7 +147,7 @@
.edit_note { .edit_note {
.markdown-area { .markdown-area {
min-height: 140px; min-height: 140px;
max-height: 430px; max-height: 500px;
} }
.note-form-actions { .note-form-actions {
background: transparent; background: transparent;
......
...@@ -126,4 +126,16 @@ module BlobHelper ...@@ -126,4 +126,16 @@ module BlobHelper
blob.size blob.size
end end
end end
def blob_svg?(blob)
blob.language && blob.language.name == 'SVG'
end
# SVGs can contain malicious JavaScript; only include whitelisted
# elements and attributes. Note that this whitelist is by no means complete
# and may omit some elements.
def sanitize_svg(blob)
blob.data = Loofah.scrub_fragment(blob.data, :strip).to_xml
blob
end
end end
...@@ -10,7 +10,7 @@ class EmailRejectionMailer < BaseMailer ...@@ -10,7 +10,7 @@ class EmailRejectionMailer < BaseMailer
subject: "[Rejected] #{@original_message.subject}" subject: "[Rejected] #{@original_message.subject}"
} }
headers['Message-ID'] = SecureRandom.hex headers['Message-ID'] = "<#{SecureRandom.hex}@#{Gitlab.config.gitlab.host}>"
headers['In-Reply-To'] = @original_message.message_id headers['In-Reply-To'] = @original_message.message_id
headers['References'] = @original_message.message_id headers['References'] = @original_message.message_id
......
...@@ -346,10 +346,10 @@ class MergeRequest < ActiveRecord::Base ...@@ -346,10 +346,10 @@ class MergeRequest < ActiveRecord::Base
# Return the set of issues that will be closed if this merge request is accepted. # Return the set of issues that will be closed if this merge request is accepted.
def closes_issues(current_user = self.author) def closes_issues(current_user = self.author)
if target_branch == project.default_branch if target_branch == project.default_branch
issues = commits.flat_map { |c| c.closes_issues(current_user) } messages = commits.map(&:safe_message) << description
issues.push(*Gitlab::ClosingIssueExtractor.new(project, current_user).
closed_by_message(description)) Gitlab::ClosingIssueExtractor.new(project, current_user).
issues.uniq(&:id) closed_by_message(messages.join("\n"))
else else
[] []
end end
......
...@@ -35,6 +35,9 @@ ...@@ -35,6 +35,9 @@
- if blob.lfs_pointer? - if blob.lfs_pointer?
= render "download", blob: blob = render "download", blob: blob
- elsif blob.text? - elsif blob.text?
- if blob_svg?(blob)
= render "image", blob: sanitize_svg(blob)
- else
= render "text", blob: blob = render "text", blob: blob
- elsif blob.image? - elsif blob.image?
= render "image", blob: blob = render "image", blob: blob
......
...@@ -49,12 +49,14 @@ if Gitlab::Metrics.enabled? ...@@ -49,12 +49,14 @@ if Gitlab::Metrics.enabled?
config.instrument_instance_methods(Gitlab::Shell) config.instrument_instance_methods(Gitlab::Shell)
config.instrument_methods(Gitlab::Git) config.instrument_methods(Gitlab::Git)
config.instrument_instance_methods(Gitlab::Git::Repository)
Gitlab::Git.constants.each do |name| Gitlab::Git.constants.each do |name|
const = Gitlab::Git.const_get(name) const = Gitlab::Git.const_get(name)
config.instrument_methods(const) if const.is_a?(Module) next unless const.is_a?(Module)
config.instrument_methods(const)
config.instrument_instance_methods(const)
end end
Dir[Rails.root.join('app', 'finders', '*.rb')].each do |path| Dir[Rails.root.join('app', 'finders', '*.rb')].each do |path|
...@@ -62,6 +64,16 @@ if Gitlab::Metrics.enabled? ...@@ -62,6 +64,16 @@ if Gitlab::Metrics.enabled?
config.instrument_instance_methods(const) config.instrument_instance_methods(const)
end end
[
:Blame, :Branch, :BranchCollection, :Blob, :Commit, :Diff, :Repository,
:Tag, :TagCollection, :Tree
].each do |name|
const = Rugged.const_get(name)
config.instrument_methods(const)
config.instrument_instance_methods(const)
end
end end
GC::Profiler.enable GC::Profiler.enable
......
...@@ -18,7 +18,7 @@ GET /ci/projects ...@@ -18,7 +18,7 @@ GET /ci/projects
Returns: Returns:
```json ```json
[ [
{ {
"id" : 271, "id" : 271,
"name" : "gitlabhq", "name" : "gitlabhq",
......
...@@ -320,3 +320,13 @@ Feature: Project Source Browse Files ...@@ -320,3 +320,13 @@ Feature: Project Source Browse Files
Then I should see download link and object size Then I should see download link and object size
And I should not see lfs pointer details And I should not see lfs pointer details
And I should see buttons for allowed commands And I should see buttons for allowed commands
@javascript
Scenario: I preview an SVG file
Given I click on "Upload file" link in repo
And I upload a new SVG file
And I fill the upload file commit message
And I fill the new branch name
And I click on "Upload file"
Given I visit the SVG file
Then I can see the new rendered SVG image
...@@ -351,6 +351,19 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -351,6 +351,19 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
expect(page).to have_content "You're not allowed to make changes to this project directly. A fork of this project has been created that you can make changes in, so you can submit a merge request." expect(page).to have_content "You're not allowed to make changes to this project directly. A fork of this project has been created that you can make changes in, so you can submit a merge request."
end end
# SVG files
step 'I upload a new SVG file' do
drop_in_dropzone test_svg_file
end
step 'I visit the SVG file' do
visit namespace_project_blob_path(@project.namespace, @project, 'new_branch_name/logo_sample.svg')
end
step 'I can see the new rendered SVG image' do
expect(find('.file-content')).to have_css('img')
end
private private
def set_new_content def set_new_content
...@@ -410,4 +423,8 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -410,4 +423,8 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
def test_image_file def test_image_file
File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif') File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif')
end end
def test_svg_file
File.join(Rails.root, 'spec', 'fixtures', 'logo_sample.svg')
end
end end
...@@ -44,19 +44,19 @@ module Gitlab ...@@ -44,19 +44,19 @@ module Gitlab
def file_name_regex def file_name_regex
@file_name_regex ||= /\A[a-zA-Z0-9_\-\.]*\z/.freeze @file_name_regex ||= /\A[a-zA-Z0-9_\-\.\@]*\z/.freeze
end end
def file_name_regex_message def file_name_regex_message
"can contain only letters, digits, '_', '-' and '.'. " "can contain only letters, digits, '_', '-', '@' and '.'. "
end end
def file_path_regex def file_path_regex
@file_path_regex ||= /\A[a-zA-Z0-9_\-\.\/]*\z/.freeze @file_path_regex ||= /\A[a-zA-Z0-9_\-\.\/\@]*\z/.freeze
end end
def file_path_regex_message def file_path_regex_message
"can contain only letters, digits, '_', '-' and '.'. Separate directories with a '/'. " "can contain only letters, digits, '_', '-', '@' and '.'. Separate directories with a '/'. "
end end
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="210px" height="210px" viewBox="0 0 210 210" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.3.2 (12043) - http://www.bohemiancoding.com/sketch -->
<title>Slice 1</title>
<desc>Created with Sketch.</desc>
<script>alert('FAIL')</script>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="logo" sketch:type="MSLayerGroup" transform="translate(0.000000, 10.000000)">
<g id="Page-1" sketch:type="MSShapeGroup">
<g id="Fill-1-+-Group-24">
<g id="Group-24">
<g id="Group">
<path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329" class="tanuki-shape"></path>
<path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26" class="tanuki-shape"></path>
<path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326" class="tanuki-shape"></path>
<path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329" class="tanuki-shape"></path>
<path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26" class="tanuki-shape"></path>
<path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326" class="tanuki-shape"></path>
<path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329" class="tanuki-shape"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
#= require behaviors/autosize
describe 'Autosize behavior', ->
beforeEach ->
fixture.set('<textarea class="js-autosize" style="resize: vertical"></textarea>')
it 'does not overwrite the resize property', ->
load()
expect($('textarea')).toHaveCss(resize: 'vertical')
load = -> $(document).trigger('page:load')
...@@ -21,4 +21,12 @@ describe Gitlab::Regex, lib: true do ...@@ -21,4 +21,12 @@ describe Gitlab::Regex, lib: true do
it { expect('Dash – is this').to match(Gitlab::Regex.project_name_regex) } it { expect('Dash – is this').to match(Gitlab::Regex.project_name_regex) }
it { expect('?gitlab').not_to match(Gitlab::Regex.project_name_regex) } it { expect('?gitlab').not_to match(Gitlab::Regex.project_name_regex) }
end end
describe 'file name regex' do
it { expect('foo@bar').to match(Gitlab::Regex.file_name_regex) }
end
describe 'file path regex' do
it { expect('foo@/bar').to match(Gitlab::Regex.file_path_regex) }
end
end end
...@@ -137,9 +137,10 @@ describe MergeRequest, models: true do ...@@ -137,9 +137,10 @@ describe MergeRequest, models: true do
describe 'detection of issues to be closed' do describe 'detection of issues to be closed' do
let(:issue0) { create :issue, project: subject.project } let(:issue0) { create :issue, project: subject.project }
let(:issue1) { create :issue, project: subject.project } let(:issue1) { create :issue, project: subject.project }
let(:commit0) { double('commit0', closes_issues: [issue0]) }
let(:commit1) { double('commit1', closes_issues: [issue0]) } let(:commit0) { double('commit0', safe_message: "Fixes #{issue0.to_reference}") }
let(:commit2) { double('commit2', closes_issues: [issue1]) } let(:commit1) { double('commit1', safe_message: "Fixes #{issue0.to_reference}") }
let(:commit2) { double('commit2', safe_message: "Fixes #{issue1.to_reference}") }
before do before do
allow(subject).to receive(:commits).and_return([commit0, commit1, commit2]) allow(subject).to receive(:commits).and_return([commit0, commit1, commit2])
...@@ -149,7 +150,9 @@ describe MergeRequest, models: true do ...@@ -149,7 +150,9 @@ describe MergeRequest, models: true do
allow(subject.project).to receive(:default_branch). allow(subject.project).to receive(:default_branch).
and_return(subject.target_branch) and_return(subject.target_branch)
expect(subject.closes_issues).to eq([issue0, issue1].sort_by(&:id)) closed = subject.closes_issues
expect(closed).to include(issue0, issue1)
end end
it 'only lists issues as to be closed if it targets the default branch' do it 'only lists issues as to be closed if it targets the default branch' do
...@@ -167,17 +170,6 @@ describe MergeRequest, models: true do ...@@ -167,17 +170,6 @@ describe MergeRequest, models: true do
expect(subject.closes_issues).to include(issue2) expect(subject.closes_issues).to include(issue2)
end end
context 'for a project with JIRA integration' do
let(:issue0) { JiraIssue.new('JIRA-123', subject.project) }
let(:issue1) { JiraIssue.new('FOOBAR-4567', subject.project) }
it 'returns sorted JiraIssues' do
allow(subject.project).to receive_messages(default_branch: subject.target_branch)
expect(subject.closes_issues).to eq([issue0, issue1])
end
end
end end
describe "#work_in_progress?" do describe "#work_in_progress?" do
......
/*!
* jQuery resize event - v1.1 - 3/14/2010
* http://benalman.com/projects/jquery-resize-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
// Script: jQuery resize event
//
// *Version: 1.1, Last updated: 3/14/2010*
//
// Project Home - http://benalman.com/projects/jquery-resize-plugin/
// GitHub - http://github.com/cowboy/jquery-resize/
// Source - http://github.com/cowboy/jquery-resize/raw/master/jquery.ba-resize.js
// (Minified) - http://github.com/cowboy/jquery-resize/raw/master/jquery.ba-resize.min.js (1.0kb)
//
// About: License
//
// Copyright (c) 2010 "Cowboy" Ben Alman,
// Dual licensed under the MIT and GPL licenses.
// http://benalman.com/about/license/
//
// About: Examples
//
// This working example, complete with fully commented code, illustrates a few
// ways in which this plugin can be used.
//
// resize event - http://benalman.com/code/projects/jquery-resize/examples/resize/
//
// About: Support and Testing
//
// Information about what version or versions of jQuery this plugin has been
// tested with, what browsers it has been tested in, and where the unit tests
// reside (so you can test it yourself).
//
// jQuery Versions - 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.6, Safari 3-4, Chrome, Opera 9.6-10.1.
// Unit Tests - http://benalman.com/code/projects/jquery-resize/unit/
//
// About: Release History
//
// 1.1 - (3/14/2010) Fixed a minor bug that was causing the event to trigger
// immediately after bind in some circumstances. Also changed $.fn.data
// to $.data to improve performance.
// 1.0 - (2/10/2010) Initial release
(function($,window,undefined){
'$:nomunge'; // Used by YUI compressor.
// A jQuery object containing all non-window elements to which the resize
// event is bound.
var elems = $([]),
// Extend $.resize if it already exists, otherwise create it.
jq_resize = $.resize = $.extend( $.resize, {} ),
timeout_id,
// Reused strings.
str_setTimeout = 'setTimeout',
str_resize = 'resize',
str_data = str_resize + '-special-event',
str_delay = 'delay',
str_throttle = 'throttleWindow';
// Property: jQuery.resize.delay
//
// The numeric interval (in milliseconds) at which the resize event polling
// loop executes. Defaults to 250.
jq_resize[ str_delay ] = 250;
// Property: jQuery.resize.throttleWindow
//
// Throttle the native window object resize event to fire no more than once
// every <jQuery.resize.delay> milliseconds. Defaults to true.
//
// Because the window object has its own resize event, it doesn't need to be
// provided by this plugin, and its execution can be left entirely up to the
// browser. However, since certain browsers fire the resize event continuously
// while others do not, enabling this will throttle the window resize event,
// making event behavior consistent across all elements in all browsers.
//
// While setting this property to false will disable window object resize
// event throttling, please note that this property must be changed before any
// window object resize event callbacks are bound.
jq_resize[ str_throttle ] = true;
// Event: resize event
//
// Fired when an element's width or height changes. Because browsers only
// provide this event for the window element, for other elements a polling
// loop is initialized, running every <jQuery.resize.delay> milliseconds
// to see if elements' dimensions have changed. You may bind with either
// .resize( fn ) or .bind( "resize", fn ), and unbind with .unbind( "resize" ).
//
// Usage:
//
// > jQuery('selector').bind( 'resize', function(e) {
// > // element's width or height has changed!
// > ...
// > });
//
// Additional Notes:
//
// * The polling loop is not created until at least one callback is actually
// bound to the 'resize' event, and this single polling loop is shared
// across all elements.
//
// Double firing issue in jQuery 1.3.2:
//
// While this plugin works in jQuery 1.3.2, if an element's event callbacks
// are manually triggered via .trigger( 'resize' ) or .resize() those
// callbacks may double-fire, due to limitations in the jQuery 1.3.2 special
// events system. This is not an issue when using jQuery 1.4+.
//
// > // While this works in jQuery 1.4+
// > $(elem).css({ width: new_w, height: new_h }).resize();
// >
// > // In jQuery 1.3.2, you need to do this:
// > var elem = $(elem);
// > elem.css({ width: new_w, height: new_h });
// > elem.data( 'resize-special-event', { width: elem.width(), height: elem.height() } );
// > elem.resize();
$.event.special[ str_resize ] = {
// Called only when the first 'resize' event callback is bound per element.
setup: function() {
// Since window has its own native 'resize' event, return false so that
// jQuery will bind the event using DOM methods. Since only 'window'
// objects have a .setTimeout method, this should be a sufficient test.
// Unless, of course, we're throttling the 'resize' event for window.
if ( !jq_resize[ str_throttle ] && this[ str_setTimeout ] ) { return false; }
var elem = $(this);
// Add this element to the list of internal elements to monitor.
elems = elems.add( elem );
// Initialize data store on the element.
$.data( this, str_data, { w: elem.width(), h: elem.height() } );
// If this is the first element added, start the polling loop.
if ( elems.length === 1 ) {
loopy();
}
},
// Called only when the last 'resize' event callback is unbound per element.
teardown: function() {
// Since window has its own native 'resize' event, return false so that
// jQuery will unbind the event using DOM methods. Since only 'window'
// objects have a .setTimeout method, this should be a sufficient test.
// Unless, of course, we're throttling the 'resize' event for window.
if ( !jq_resize[ str_throttle ] && this[ str_setTimeout ] ) { return false; }
var elem = $(this);
// Remove this element from the list of internal elements to monitor.
elems = elems.not( elem );
// Remove any data stored on the element.
elem.removeData( str_data );
// If this is the last element removed, stop the polling loop.
if ( !elems.length ) {
clearTimeout( timeout_id );
}
},
// Called every time a 'resize' event callback is bound per element (new in
// jQuery 1.4).
add: function( handleObj ) {
// Since window has its own native 'resize' event, return false so that
// jQuery doesn't modify the event object. Unless, of course, we're
// throttling the 'resize' event for window.
if ( !jq_resize[ str_throttle ] && this[ str_setTimeout ] ) { return false; }
var old_handler;
// The new_handler function is executed every time the event is triggered.
// This is used to update the internal element data store with the width
// and height when the event is triggered manually, to avoid double-firing
// of the event callback. See the "Double firing issue in jQuery 1.3.2"
// comments above for more information.
function new_handler( e, w, h ) {
var elem = $(this),
data = $.data( this, str_data );
// If called from the polling loop, w and h will be passed in as
// arguments. If called manually, via .trigger( 'resize' ) or .resize(),
// those values will need to be computed.
data.w = w !== undefined ? w : elem.width();
data.h = h !== undefined ? h : elem.height();
old_handler.apply( this, arguments );
};
// This may seem a little complicated, but it normalizes the special event
// .add method between jQuery 1.4/1.4.1 and 1.4.2+
if ( $.isFunction( handleObj ) ) {
// 1.4, 1.4.1
old_handler = handleObj;
return new_handler;
} else {
// 1.4.2+
old_handler = handleObj.handler;
handleObj.handler = new_handler;
}
}
};
function loopy() {
// Start the polling loop, asynchronously.
timeout_id = window[ str_setTimeout ](function(){
// Iterate over all elements to which the 'resize' event is bound.
elems.each(function(){
var elem = $(this),
width = elem.width(),
height = elem.height(),
data = $.data( this, str_data );
// If element size has changed since the last time, update the element
// data store and trigger the 'resize' event.
if ( width !== data.w || height !== data.h ) {
elem.trigger( str_resize, [ data.w = width, data.h = height ] );
}
});
// Loop.
loopy();
}, jq_resize[ str_delay ] );
};
})(jQuery,this);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment