Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*******************************************************************************
* Copyright (c) 2014-2015 BSI Business Systems Integration AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BSI Business Systems Integration AG - initial API and implementation
******************************************************************************/
/**
* JQuery plugin with scout extensions
*/
// === internal methods ===
/**
* Returns false when the component display is 'none' or visibility is 'hidden', otherwise true.
* Note: this gives other results than $.is(':visible'), since that method will also return false
* when a component has absolute positioning and no width and height is defined (well, you cannot
* see a component with a style like this, but technically it is not set to 'not visible').
*/
function elemVisible(elem) {
// Check if element itself is hidden by its own style attribute
if (isHidden(elem.style)) {
return false;
}
// Must use correct window for element / computedStyle
var myWindow = elem.ownerDocument.defaultView;
// Check if element itself is hidden by external style-sheet
if (isHidden(myWindow.getComputedStyle(elem))) {
return false;
}
// Else visible
return true;
// ----- Helper functions -----
function isHidden(style) {
return style.display === 'none' || style.visibility === 'hidden';
}
}
function explodeShorthandProperties(properties) {
var newProperties = [];
properties.forEach(function(prop) {
// shorthand css properties may not be copied directly (at least not in firefox) -> copy the actual properties
if (prop === 'margin' || prop === 'padding') {
newProperties.push(prop + '-top');
newProperties.push(prop + '-right');
newProperties.push(prop + '-bottom');
newProperties.push(prop + '-left');
} else if (prop === 'border') {
newProperties.push('border-top-style');
newProperties.push('border-right-style');
newProperties.push('border-bottom-style');
newProperties.push('border-left-style');
newProperties.push('border-top-color');
newProperties.push('border-right-color');
newProperties.push('border-bottom-color');
newProperties.push('border-left-color');
newProperties.push('border-top-width');
newProperties.push('border-right-width');
newProperties.push('border-bottom-width');
newProperties.push('border-left-width');
} else {
newProperties.push(prop);
}
});
return newProperties;
}
// === $ extensions ===
// used by some animate functions
$.removeThis = function() {
$(this).remove();
};
/**
* Convenience function that can be used as an jQuery event handler, when this
* event should be "swallowed". Technically, this function calls preventDefault(),
* stopPropagation() and stopImmediatePropagation() on the event.
*
* Note: "return false" is equal to preventDefault() and stopPropagation(), but
* not stopImmediatePropagation().
*/
$.suppressEvent = function(event) {
if (event) {
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
}
};
/**
* If the event target is disabled (according to $.fn.isEnabled()), the event is suppressed
* and the method returns true. Otherwise, false is returned.
*/
$.suppressEventIfDisabled = function(event, $target) {
$target = $target || $(event.target);
if (!$target.isEnabled()) {
$.suppressEvent(event);
return true;
}
return false;
};
/**
* Implements the 'debounce' pattern. The given function fx is executed after a certain delay
* (in milliseconds), but if the same function is called a second time within the waiting time,
* the timer is reset. The default value for 'delay' is 250 ms.
*/
$.debounce = function(fx, delay) {
delay = (delay !== undefined) ? delay : 250;
var timeoutId = null;
return function() {
var that = this,
args = arguments;
clearTimeout(timeoutId);
timeoutId = setTimeout(function() {
fx.apply(that, args);
}, delay);
};
};
/**
* Executes the given function. Further calls to the same function are delayed by the given delay
* (default 250ms). This is similar to $.debounce() but ensures that function is called at least
* every 'delay' milliseconds. Can be useful to prevent too many function calls, e.g. from UI events.
*/
$.throttle = function(fx, delay) {
delay = (delay !== undefined) ? delay : 250;
var timeoutId = null;
var lastExecution;
return function() {
var that = this,
args = arguments,
now = new Date().getTime(),
callFx = function() {
lastExecution = now;
fx.apply(that, args);
};
if (lastExecution && lastExecution + delay > now) {
clearTimeout(timeoutId);
timeoutId = setTimeout(function() {
callFx();
}, delay);
} else {
callFx();
}
};
};
/**
* Returns a function which negates the return value of the given function when called.
*/
$.negate = function(fx) {
return function() {
return !fx.apply(this, arguments);
};
};
/**
* color calculation
*/
$.colorOpacity = function(hex, opacity) {
// validate hex string
hex = String(hex).replace(/[^0-9a-f]/gi, '');
if (hex.length < 6) {
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
opacity = opacity || 0;
// convert to decimal and change luminosity
var rgb = '#';
for (var i = 0; i < 3; i++) {
var c = parseInt(hex.substr(i * 2, 2), 16);
c = Math.round(Math.min(Math.max(0, 255 - (255 - c) * opacity), 255)).toString(16);
rgb += ('00' + c).substr(c.length);
}
return rgb;
};
/**
* from http://api.jquery.com/jquery.getscript/
*/
$.getCachedScript = function(url, options) {
options = $.extend(options || {}, {
dataType: 'script',
cache: true,
url: url
});
return $.ajax(options);
};
$.pxToNumber = function(pixel) {
if (!pixel) {
// parseFloat would return NaN if pixel is '' or undefined
return 0;
}
// parseFloat ignores 'px' and just extracts the number
return parseFloat(pixel, 10);
};
// === $.prototype extensions ===
/**
* @param element string. Example = <input>
* @param cssClass (optional) class attribute
* @param text (optional) adds a child text-node with given text (no HTML content)
*/
$.fn.makeElement = function(element, cssClass, text) {
var myDocument = this.document(true);
if (myDocument === undefined || element === undefined) {
return new Error('missing arguments: document, element');
}
var $element = $(element, myDocument);
if (cssClass) {
$element.addClass(cssClass);
}
if (text) {
$element.text(text);
}
return $element;
};
/**
* Creates a DIV element in the current document. The function adds an unselectable attribute,
* if this is required by the current device (@see Device.js). When you don't want the (un-)
* selectable behavior use makeElement('<div>').
*
* @param cssClass (optional) string added to the 'class' attribute
* @param text (optional) string used as inner text
*/
$.fn.makeDiv = function(cssClass, text) {
var unselectable = scout.device.unselectableAttribute,
$div = this.makeElement('
', cssClass, text);
if (unselectable.key) {
$div.attr(unselectable.key, unselectable.value);
}
return $div;
};
$.fn.makeSpan = function(cssClass, text) {
return this.makeElement('', cssClass, text);
};
/**
* @return HTML document reference (ownerDocument) of the HTML element.
* @param domElement (optional) if true this function returns a JQuery object, otherwise only the DOM element is returned
*/
$.fn.document = function(domElement) {
var myDocument = this.length ? this[0].ownerDocument : null;
return domElement ? myDocument : $(myDocument);
};
/**
* @return HTML window reference (defaultView) of the HTML element
* @param domElement (optional) if true this function returns a JQuery object, otherwise only the DOM element is returned
*/
$.fn.window = function(domElement) {
var myDocument = this.document(true),
myWindow = myDocument ? myDocument.defaultView : null;
return domElement ? myWindow : $(myWindow);
};
/**
* @return HTML document reference (ownerDocument) of the HTML element.
* @param domElement (optional) if true this function returns a JQuery object, otherwise only the DOM element is returned
*/
$.fn.activeElement = function(domElement) {
var myDocument = this.document(true),
activeElement = myDocument ? myDocument.activeElement : null;
return domElement ? activeElement : $(activeElement);
};
/**
* @return the BODY element of the HTML document in which the current HTML element is placed.
*/
$.fn.body = function() {
return $('body', this.document(true));
};
/**
* @return the closest DOM element that has the 'scout' class.
* @param domElement (optional) if true this function returns a JQuery object, otherwise only the DOM element is returned
*/
$.fn.entryPoint = function(domElement) {
var $element = this.closest('.scout');
return domElement ? $element[0] : $element;
};
// prepend - and return new div for chaining
$.fn.prependDiv = function(cssClass, text) {
return this.makeDiv(cssClass, text).prependTo(this);
};
// append - and return new div for chaining
$.fn.appendDiv = function(cssClass, text) {
return this.makeDiv(cssClass, text).appendTo(this);
};
$.fn.prependElement = function(element, cssClass, text) {
return this.makeElement(element, cssClass, text).prependTo(this);
};
$.fn.appendElement = function(element, cssClass, text) {
return this.makeElement(element, cssClass, text).appendTo(this);
};
// insert after - and return new div for chaining
$.fn.afterDiv = function(cssClass, text) {
return this.makeDiv(cssClass, text).insertAfter(this);
};
// insert before - and return new div for chaining
$.fn.beforeDiv = function(cssClass, text) {
return this.makeDiv(cssClass, text).insertBefore(this);
};
$.fn.appendSpan = function(cssClass, text) {
return this.makeSpan(cssClass, text).appendTo(this);
};
$.fn.appendBr = function(cssClass) {
return this.makeElement(' ', cssClass).appendTo(this);
};
$.fn.appendTextNode = function(text) {
return $(this.document(true).createTextNode(text)).appendTo(this);
};
$.fn.makeSVG = function(type, cssClass, text, id) {
var myDocument = this.document(true);
if (myDocument === undefined || type === undefined) {
return new Error('missing arguments: document, type');
}
var $svg = $(myDocument.createElementNS('http://www.w3.org/2000/svg', type));
if (cssClass) {
$svg.attrSVG('class', cssClass);
}
if (text) {
$svg.text(text);
}
if (id !== undefined) {
$svg.attrSVG('id', id);
}
return $svg;
};
// append SVG
$.fn.appendSVG = function(type, cssClass, text, id) {
return this.makeSVG(type, cssClass, text, id).appendTo(this);
};
// attr and class handling for svg
$.fn.attrSVG = function(attributeName, value) {
if (this.length === 0) { // shortcut for empty collections
return this;
}
if (this.length === 1) { // shortcut for single element collections
this[0].setAttribute(attributeName, value);
return this;
}
return this.each(function() {
this.setAttribute(attributeName, value);
});
};
$.fn.removeAttrSVG = function(attributeName) {
if (this.length === 0) { // shortcut for empty collections
return this;
}
if (this.length === 1) { // shortcut for single element collections
this[0].removeAttribute(attributeName);
return this;
}
return this.each(function() {
this.removeAttribute(attributeName);
});
};
$.fn.attrXLINK = function(attributeName, value) {
if (this.length === 0) { // shortcut for empty collections
return this;
}
if (this.length === 1) { // shortcut for single element collections
this[0].setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:' + attributeName, value);
return this;
}
return this.each(function() {
this.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:' + attributeName, value);
});
};
$.fn.addClassSVG = function(cssClass) {
var old;
if (this.length === 0) { // shortcut for empty collections
return this;
}
if (this.length === 1) { // shortcut for single element collections
if (!this.hasClassSVG(cssClass)) {
old = this[0].getAttribute('class');
this[0].setAttribute('class', scout.strings.join(' ', old, cssClass).trim());
}
return this;
}
return this.each(function() {
if (!$(this).hasClassSVG(cssClass)) {
old = this.getAttribute('class');
this.setAttribute('class', scout.strings.join(' ', old, cssClass).trim());
}
});
};
$.fn.removeClassSVG = function(cssClass) {
var old;
if (this.length === 0) { // shortcut for empty collections
return this;
}
if (this.length === 1) { // shortcut for single element collections
old = ' ' + this[0].getAttribute('class') + ' ';
this[0].setAttribute('class', old.replace(' ' + cssClass + ' ', ' ').trim());
return this;
}
return this.each(function() {
var old = ' ' + this.getAttribute('class') + ' ';
this.setAttribute('class', old.replace(' ' + cssClass + ' ', ' ').trim());
});
};
$.fn.hasClassSVG = function(cssClass) {
var old = ' ' + this[0].getAttribute('class') + ' ';
return old.indexOf(' ' + cssClass + ' ') !== -1;
};
// select one and deselect siblings
$.fn.selectOne = function() {
this.siblings().removeClass('selected');
this.addClass('selected');
return this;
};
$.fn.select = function(selected) {
return this.toggleClass('selected', !!selected);
};
$.fn.isSelected = function() {
return this.hasClass('selected');
};
$.fn.setEnabled = function(enabled) {
enabled = !!enabled;
this.toggleClass('disabled', !enabled);
// Toggle disabled attribute for elements that support it (see http://www.w3.org/TR/html5/disabled-elements.html)
if (this.is('button, input, select, textarea, optgroup, option, fieldset')) {
this.toggleAttr('disabled', !enabled);
}
return this;
};
$.fn.isEnabled = function() {
return !this.hasClass('disabled');
};
$.fn.setVisible = function(visible) {
var i, elem;
for (i = 0; i < this.length; i++) {
elem = this[i];
if (elemVisible(elem) != visible) {
if (visible) {
this.show();
} else {
this.hide();
}
}
}
return this;
};
$.fn.isDisplayNone = function() {
return this.css('display') === 'none';
};
$.fn.setTabbable = function(tabbable) {
return this.attr('tabIndex', tabbable ? 0 : null);
};
$.fn.icon = function(iconId) {
var icon, $icon = this.data('$icon');
if (iconId) {
icon = scout.icons.parseIconId(iconId);
if (icon.isFontIcon()) {
getOrCreateIconElement.call(this, $icon, '')
.addClass(icon.appendCssClass('font-icon'))
.addClass('icon')
.text(icon.iconCharacter);
} else {
getOrCreateIconElement.call(this, $icon, '')
.attr('src', icon.iconUrl)
.addClass('icon');
}
} else {
removeIconElement.call(this, $icon);
}
return this;
// ----- Helper functions -----
function getOrCreateIconElement($icon, newElement) {
// If element type does not match existing element, remove the existing element (e.g. when changing from font-icon to picture icon)
if ($icon && !$icon.is(newElement.replace(/[<>]/g, ''))) {
removeIconElement.call(this, $icon);
$icon = null;
}
// Create new element if necessary
if (!$icon) {
$icon = $(newElement);
this.data('$icon', $icon);
this.prepend($icon);
}
return $icon;
}
function removeIconElement($icon) {
if ($icon) {
$icon.remove();
}
this.removeData('$icon');
}
};
$.fn.placeholder = function(placeholder) {
return this.toggleAttr('placeholder', !!placeholder, placeholder);
};
$.fn.isVisible = function() {
return elemVisible(this[0]);
};
$.fn.isEveryParentVisible = function() {
var everyParentVisible = true;
this.parents().each(function() {
if (!$(this).isVisible()) {
everyParentVisible = false;
return false;
}
});
return everyParentVisible;
};
/**
* @return true if the element is attached (= is in the dom tree), false if not
*/
$.fn.isAttached = function() {
return $.contains(this.document(true).documentElement, this[0]);
};
/**
* Returns the first parent which is scrollable
*/
$.fn.scrollParent = function() {
var $elem = this;
while ($elem.length > 0) {
if ($elem.data('scrollable')) {
return $elem;
}
$elem = $elem.parent();
}
return $();
};
/**
* Returns every parent which is scrollable
*/
$.fn.scrollParents = function() {
var $scrollParents = $(),
$elem = this;
while ($elem.length > 0) {
if ($elem.data('scrollable')) {
$scrollParents.push($elem);
}
$elem = $elem.parent();
}
return $scrollParents;
};
// most used animate
$.fn.animateAVCSD = function(attr, value, complete, step, duration) {
var properties = {};
var options = {};
properties[attr] = value;
if (complete) {
options.complete = complete;
}
if (step) {
options.step = step;
}
if (duration) {
options.duration = duration;
}
options.queue = false;
this.animate(properties, options);
return this;
};
// SVG animate, array contains attr, endValue + startValue
$.fn.animateSVG = function(attr, endValue, duration, complete, withoutTabIndex) {
return this.each(function() {
var startValue = parseFloat($(this).attr(attr));
if (withoutTabIndex) {
var oldComplete = complete;
complete = function() {
if (oldComplete) {
oldComplete.call(this);
}
$(this).removeAttr('tabindex');
};
}
$(this).animate({
tabIndex: 0
}, {
step: function(now, fx) {
this.setAttribute(attr, startValue + (endValue - startValue) * fx.pos);
},
duration: duration,
complete: complete,
queue: false
});
});
};
$.fn.addClassForAnimation = function(className, options) {
var defaultOptions = {
classesToRemove: className
};
options = $.extend({}, defaultOptions, options);
this.addClass(className);
this.oneAnimationEnd(function() {
// remove class, otherwise animation will be executed each time the element changes it's visibility (attach/rerender),
// and even each time when the css classes change
this.removeClass(options.classesToRemove);
// delay must be greater than css animation duration
}.bind(this));
};
$.fn.oneAnimationEnd = function(selector, data, handler) {
this.one('animationend webkitAnimationEnd', selector, data, handler);
};
/**
* Animates from old to new width
*/
$.fn.cssWidthAnimated = function(oldWidth, newWidth, opts) {
opts = opts || {};
opts.duration = scout.nvl(opts.duration, 300);
// Reset to old width first
this.cssWidth(oldWidth);
// Then animate to new width
this.animate({
width: newWidth
}, opts);
return this;
};
$.fn.cssHeightAnimated = function(oldHeight, newHeight, opts) {
opts = opts || {};
opts.duration = scout.nvl(opts.duration, 300);
// Reset to old height first
this.cssHeight(oldHeight);
// Then animate to new height
this.animate({
height: newHeight
}, opts);
return this;
};
$.fn.cssLeftAnimated = function(from, to, opts) {
opts = opts || {};
opts.duration = scout.nvl(opts.duration, 300);
// Reset to from first
this.cssLeft(from);
// Then animate to new width
this.animate({
left: to
}, opts);
return this;
};
$.fn.cssTopAnimated = function(from, to, opts) {
opts = opts || {};
opts.duration = scout.nvl(opts.duration, 300);
// Reset to from first
this.cssTop(from);
// Then animate to new pos
this.animate({
top: to
}, opts);
return this;
};
$.fn.cssAnimated = function(fromVals, toVals, opts) {
opts = opts || {};
opts.duration = scout.nvl(opts.duration, 300);
// Reset to from first
this.css(fromVals);
// Then animate to new pos
this.animate(toVals, opts);
return this;
};
// over engineered animate
$.fn.widthToContent = function(opts) {
var oldW = this.outerWidth(),
newW = this.css('width', 'auto').outerWidth();
this.cssWidthAnimated(oldW, newW, opts);
return this;
};
/**
* Offset to a specific ancestor and not to the document as offset() would do.
* Not the same as position() which returns the position relative to the offset parent.
*/
$.fn.offsetTo = function($to) {
var toOffset = $to.offset(),
offset = this.offset();
return {
top: offset.top - toOffset.top,
left: offset.left - toOffset.left
};
};
$.fn.cssLeft = function(position) {
return this.cssPxValue('left', position);
};
$.fn.cssTop = function(position) {
return this.cssPxValue('top', position);
};
$.fn.cssBottom = function(position) {
return this.cssPxValue('bottom', position);
};
$.fn.cssRight = function(position) {
return this.cssPxValue('right', position);
};
$.fn.cssWidth = function(width) {
return this.cssPxValue('width', width);
};
$.fn.cssHeight = function(height) {
return this.cssPxValue('height', height);
};
$.fn.cssLineHeight = function(height) {
return this.cssPxValue('line-height', height);
};
$.fn.cssPxValue = function(prop, value) {
if (value === undefined) {
return $.pxToNumber(this.css(prop));
}
return this.css(prop, value + 'px');
};
$.fn.cssMarginLeft = function(value) {
return this.cssPxValue('margin-left', value);
};
$.fn.cssMarginBottom = function(value) {
return this.cssPxValue('margin-bottom', value);
};
$.fn.cssMarginRight = function(value) {
return this.cssPxValue('margin-right', value);
};
$.fn.cssMarginTop = function(value) {
return this.cssPxValue('margin-top', value);
};
$.fn.cssMarginX = function(value) {
if (value === undefined) {
return this.cssMarginLeft() + this.cssMarginRight();
}
this.cssMarginLeft(value);
this.cssMarginRight(value);
};
$.fn.cssMarginY = function(value) {
if (value === undefined) {
return this.cssMarginTop() + this.cssMarginBottom();
}
this.cssMarginTop(value);
this.cssMarginBottom(value);
};
$.fn.cssPaddingTop = function(value) {
return this.cssPxValue('padding-top', value);
};
$.fn.cssBorderBottomWidth = function(value) {
return this.cssPxValue('border-bottom-width', value);
};
$.fn.cssBorderLeftWidth = function(value) {
return this.cssPxValue('border-left-width', value);
};
$.fn.cssBorderRightWidth = function(value) {
return this.cssPxValue('border-right-width', value);
};
$.fn.cssBorderTopWidth = function(value) {
return this.cssPxValue('border-top-width', value);
};
$.fn.cssBorderWidthY = function(value) {
if (value === undefined) {
return this.cssBorderTopWidth() + this.cssBorderBottomWidth();
}
this.cssBorderTopWidth(value);
this.cssBorderBottomWidth(value);
};
$.fn.cssBorderWidthX = function(value) {
if (value === undefined) {
return this.cssBorderLeftWidth() + this.cssBorderRightWidth();
}
this.cssBorderLeftWidth(value);
this.cssBorderRightWidth(value);
};
/**
* Bottom of a html element without margin and border relative to offset parent. Expects border-box model.
*/
$.fn.innerBottom = function() {
return this.position().top + this.outerHeight(true) - this.cssMarginBottom() - this.cssBorderBottomWidth();
};
/**
* Right of a html element without margin and border relative to offset parent. Expects border-box model.
*/
$.fn.innerRight = function() {
return this.position().left + this.outerWidth(true) - this.cssMarginRight() - this.cssBorderRightWidth();
};
$.fn.copyCss = function($origin, props) {
var properties = props.split(' ');
var $this = this;
properties = explodeShorthandProperties(properties);
properties.forEach(function(prop) {
$this.css(prop, $origin.css(prop));
});
return $this;
};
$.fn.copyCssIfGreater = function($origin, props) {
var properties = props.split(' ');
var $this = this;
properties = explodeShorthandProperties(properties);
properties.forEach(function(prop) {
var originValue = $.pxToNumber($origin.css(prop));
var thisValue = $.pxToNumber($this.css(prop));
if (originValue > thisValue) {
$this.css(prop, originValue + 'px');
}
});
return $this;
};
$.fn.copyCssClasses = function($other, classString) {
var classes = classString.split(' ');
var $this = this;
classes.forEach(function(cssClass) {
if ($other.hasClass(cssClass)) {
$this.addClass(cssClass);
}
});
return $this;
};
$.fn.disableSpellcheck = function() {
return this.attr('spellcheck', false);
};
/**
* Returns whether the current element is the given element or has a child which is the given element.
*/
$.fn.isOrHas = function(elem) {
return this[0] === elem || this.has(elem).length > 0;
};
/**
* Makes any element movable with the mouse. If the argument '$handle' is missing, the entire
* element can be used as a handle.
*
* A callback function can be passed as second argument (optional). The function is called for
* every change of the draggable's position with an object as argument:
* { top: (top pixels), left: (left pixels) }
*/
$.fn.makeDraggable = function($handle, callback) {
var $draggable = this;
$handle = $handle || $draggable;
return $handle.on('mousedown.draggable', function(event) {
var orig_offset = $draggable.offset();
var orig_event = event;
var handleWidth = $handle.width();
var windowWidth = $handle.window().width();
var windowHeight = $handle.window().height();
$handle.parents()
.on('mousemove.dragging', function(event) {
var top = orig_offset.top + (event.pageY - orig_event.pageY);
var left = orig_offset.left + (event.pageX - orig_event.pageX);
// do not drop outside of viewport (and leave a margin of 100 pixels)
left = Math.max(100 - handleWidth, left);
left = Math.min(windowWidth - 100, left);
top = Math.max(0, top); // must not be dragged outside of top, otherwise dragging back is impossible
top = Math.min(windowHeight - 100, top);
var newOffset = {
top: top,
left: left
};
$draggable.offset(newOffset);
callback && callback(newOffset);
})
.on('mouseup.dragging', function(e) {
$handle.parents().off('.dragging');
});
event.preventDefault();
});
};
/**
* Calls jQuery.fadeOut() and then removes the element from the DOM.
* Default fade-out duration is 150 ms.
*/
$.fn.fadeOutAndRemove = function(duration, callback) {
if (callback === undefined && typeof duration === 'function') {
callback = duration;
duration = undefined;
}
duration = scout.nvl(duration, 150);
this.stop(true).fadeOut(duration, function() {
$(this).remove();
if (callback) {
callback.call(this);
}
});
};
var _oldhide = $.fn.hide;
$.fn.hide = function() {
this.trigger('hide');
var returnValue = _oldhide.apply(this, arguments);
return returnValue;
};
//TODO [6.1] cgu: provide alternative methods for show and hide which just change the css class (this.addClass('hidden');). Should be a lot faster because it is not necessary to remember any state.
/**
* Sets the given 'text' as text to the jQuery element, using the text() function (i.e. HTML is encoded automatically).
* If the text does not contain any non-space characters, the text ' ' is set instead (using the html() function).
* If an 'emptyCssClass' is provided, this CSS class is removed in the former and added in the later case.
*/
$.fn.textOrNbsp = function(text, emptyCssClass) {
if (scout.strings.hasText(text)) {
this.text(text);
if (emptyCssClass) {
this.removeClass(emptyCssClass);
}
} else {
this.html(' ');
if (emptyCssClass) {
this.addClass(emptyCssClass);
}
}
return this;
};
/**
* Same as "textOrNbsp", but with html (caller is responsible for encoding).
*/
$.fn.htmlOrNbsp = function(html, emptyCssClass) {
if (scout.strings.hasText(html)) {
this.html(html);
if (emptyCssClass) {
this.removeClass(emptyCssClass);
}
} else {
this.html(' ');
if (emptyCssClass) {
this.addClass(emptyCssClass);
}
}
return this;
};
/**
* Like toggleClass(), this toggles a HTML attribute on a set of jquery elements.
*
* @param attr
* Name of the attribute to toggle.
* @param state
* Specifies if the attribute should be added or removed (based on whether the argument is truthy or falsy).
* If this argument is not defined, the attribute is added when it exists, and vice-versa. If this behavior
* is not desired, explicitly cast the argument to a boolean using "!!".
* @param value
* Value to use when adding the attribute.
* If this argument is not specified, 'attr' is used as value.
*/
$.fn.toggleAttr = function(attr, state, value) {
if (!attr) {
return this;
}
if (value === undefined) {
value = attr;
}
return this.each(function() {
var $element = $(this);
if (state === undefined) {
// set state according to the current value
state = ($element.attr(attr) === undefined);
}
if (state) {
// set attr
$element.attr(attr, value);
} else {
// remove attr
$element.removeAttr(attr);
}
});
};
$.fn.backupSelection = function() {
var field = this[0];
if (field && field === this.activeElement(true)) {
return {
selectionStart: field.selectionStart,
selectionEnd: field.selectionEnd,
selectionDirection: field.selectionDirection
};
}
return null;
};
$.fn.restoreSelection = function(selection) {
var field = this[0];
if (field && field === this.activeElement(true) && selection) {
field.setSelectionRange(selection.selectionStart, selection.selectionEnd, selection.selectionDirection);
}
};
/**
* If the given value is "truthy", it is set as attribute on the target. Otherwise, the attribute is removed.
*/
$.fn.attrOrRemove = function(attributeName, value) {
if (value) {
$(this).attr(attributeName, value);
} else {
$(this).removeAttr(attributeName);
}
};
$.fn.appendAppLink = function(appLinkBean, func) {
return this.appendSpan().appLink(appLinkBean, func);
};
/**
* @param func Either a function to be called when the app link has been clicked.
* Or an object with a method named _onAppLinkAction (e.g. an instance of BeanField).
*/
$.fn.appLink = function(appLinkBean, func) {
if (typeof func === 'object' && func._onAppLinkAction) {
func = func._onAppLinkAction.bind(func);
}
return this.addClass('app-link')
.text(appLinkBean.name)
.attr('tabindex', '0')
.attr('data-ref', appLinkBean.ref)
.unfocusable()
.on('click', func);
};
/**
* Adds the class 'unfocusable' to current result set. The class is not used for styling purposes
* but has a meaning to the FocusManager.
*/
$.fn.unfocusable = function() {
return this.addClass('unfocusable');
};
/**
* Select all text within an element, e.g. within a content editable div element.
*/
$.fn.selectAllText = function() {
var range,
myDocument = this.document(true),
myWindow = this.window(true),
element = this[0];
if (myDocument.body.createTextRange) {
range = myDocument.body.createTextRange();
range.moveToElementText(element);
range.select();
return;
}
if (myWindow.getSelection) {
range = myDocument.createRange();
range.selectNodeContents(element);
myWindow.getSelection().removeAllRanges();
myWindow.getSelection().addRange(range);
}
};
/**
* Checks if content is truncated.
*/
$.fn.isContentTruncated = function() {
return this[0].scrollWidth > this[0].clientWidth;
};
// FIXME awe: (graph) consider moving this function to DoubleClickHandler.js
/**
* This function is used to distinct between single and double clicks.
* Instead of executing a handler immediately when the first click occurs,
* we wait for a given timeout (or by default 300 ms) to check if it is followed by a second click.
* This will delay the execution of a single click a bit, so you should use this function wisely.
*/
$.fn.onSingleOrDoubleClick = function(singleClickFunc, doubleClickFunc, timeout) {
return this.each(function() {
var that = this,
numClicks = 0,
timeout = timeout || 300;
$(this).on('click', function(event) {
numClicks++;
if (numClicks == 1) {
setTimeout(function() {
if (numClicks == 1) {
singleClickFunc.call(that, event);
} else {
doubleClickFunc.call(that, event);
}
numClicks = 0;
}, timeout);
}
});
});
};