Initial code using Drupal 6.38
266
misc/ahah.js
Normal file
|
@ -0,0 +1,266 @@
|
|||
|
||||
/**
|
||||
* Provides AJAX-like page updating via AHAH (Asynchronous HTML and HTTP).
|
||||
*
|
||||
* AHAH is a method of making a request via Javascript while viewing an HTML
|
||||
* page. The request returns a small chunk of HTML, which is then directly
|
||||
* injected into the page.
|
||||
*
|
||||
* Drupal uses this file to enhance form elements with #ahah[path] and
|
||||
* #ahah[wrapper] properties. If set, this file will automatically be included
|
||||
* to provide AHAH capabilities.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Attaches the ahah behavior to each ahah form element.
|
||||
*/
|
||||
Drupal.behaviors.ahah = function(context) {
|
||||
for (var base in Drupal.settings.ahah) {
|
||||
if (!$('#'+ base + '.ahah-processed').size()) {
|
||||
var element_settings = Drupal.settings.ahah[base];
|
||||
|
||||
$(element_settings.selector).each(function() {
|
||||
element_settings.element = this;
|
||||
var ahah = new Drupal.ahah(base, element_settings);
|
||||
});
|
||||
|
||||
$('#'+ base).addClass('ahah-processed');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* AHAH object.
|
||||
*/
|
||||
Drupal.ahah = function(base, element_settings) {
|
||||
// Set the properties for this object.
|
||||
this.element = element_settings.element;
|
||||
this.selector = element_settings.selector;
|
||||
this.event = element_settings.event;
|
||||
this.keypress = element_settings.keypress;
|
||||
this.url = element_settings.url;
|
||||
this.wrapper = '#'+ element_settings.wrapper;
|
||||
this.effect = element_settings.effect;
|
||||
this.method = element_settings.method;
|
||||
this.progress = element_settings.progress;
|
||||
this.button = element_settings.button || { };
|
||||
this.immutable = element_settings.immutable;
|
||||
this.buildId = null;
|
||||
|
||||
if (this.effect == 'none') {
|
||||
this.showEffect = 'show';
|
||||
this.hideEffect = 'hide';
|
||||
this.showSpeed = '';
|
||||
}
|
||||
else if (this.effect == 'fade') {
|
||||
this.showEffect = 'fadeIn';
|
||||
this.hideEffect = 'fadeOut';
|
||||
this.showSpeed = 'slow';
|
||||
}
|
||||
else {
|
||||
this.showEffect = this.effect + 'Toggle';
|
||||
this.hideEffect = this.effect + 'Toggle';
|
||||
this.showSpeed = 'slow';
|
||||
}
|
||||
|
||||
// Record the form action and target, needed for iFrame file uploads.
|
||||
var form = $(this.element).parents('form');
|
||||
this.form_action = form.attr('action');
|
||||
this.form_target = form.attr('target');
|
||||
this.form_encattr = form.attr('encattr');
|
||||
|
||||
// Set the options for the ajaxSubmit function.
|
||||
// The 'this' variable will not persist inside of the options object.
|
||||
var ahah = this;
|
||||
var options = {
|
||||
url: ahah.url,
|
||||
data: ahah.button,
|
||||
beforeSubmit: function(form_values, element_settings, options) {
|
||||
return ahah.beforeSubmit(form_values, element_settings, options);
|
||||
},
|
||||
beforeSend: function(request, options) {
|
||||
return ahah.beforeSend(request, options);
|
||||
},
|
||||
success: function(response, status) {
|
||||
// Sanity check for browser support (object expected).
|
||||
// When using iFrame uploads, responses must be returned as a string.
|
||||
if (typeof(response) == 'string') {
|
||||
response = Drupal.parseJson(response);
|
||||
}
|
||||
return ahah.success(response, status);
|
||||
},
|
||||
complete: function(response, status) {
|
||||
ahah.complete(response, status);
|
||||
if (status == 'error' || status == 'parsererror') {
|
||||
return ahah.error(response, ahah.url);
|
||||
}
|
||||
},
|
||||
dataType: 'json',
|
||||
type: 'POST'
|
||||
};
|
||||
|
||||
// Bind the ajaxSubmit function to the element event.
|
||||
$(element_settings.element).bind(element_settings.event, function() {
|
||||
$(element_settings.element).parents('form').ajaxSubmit(options);
|
||||
return false;
|
||||
});
|
||||
// If necessary, enable keyboard submission so that AHAH behaviors
|
||||
// can be triggered through keyboard input as well as e.g. a mousedown
|
||||
// action.
|
||||
if (element_settings.keypress) {
|
||||
$(element_settings.element).keypress(function(event) {
|
||||
// Detect enter key.
|
||||
if (event.keyCode == 13) {
|
||||
$(element_settings.element).trigger(element_settings.event);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handler for the form redirection submission.
|
||||
*/
|
||||
Drupal.ahah.prototype.beforeSubmit = function (form_values, element, options) {
|
||||
// Disable the element that received the change.
|
||||
$(this.element).addClass('progress-disabled').attr('disabled', true);
|
||||
|
||||
// Insert progressbar or throbber.
|
||||
if (this.progress.type == 'bar') {
|
||||
var progressBar = new Drupal.progressBar('ahah-progress-' + this.element.id, eval(this.progress.update_callback), this.progress.method, eval(this.progress.error_callback));
|
||||
if (this.progress.message) {
|
||||
progressBar.setProgress(-1, this.progress.message);
|
||||
}
|
||||
if (this.progress.url) {
|
||||
progressBar.startMonitoring(this.progress.url, this.progress.interval || 1500);
|
||||
}
|
||||
this.progress.element = $(progressBar.element).addClass('ahah-progress ahah-progress-bar');
|
||||
this.progress.object = progressBar;
|
||||
$(this.element).after(this.progress.element);
|
||||
}
|
||||
else if (this.progress.type == 'throbber') {
|
||||
this.progress.element = $('<div class="ahah-progress ahah-progress-throbber"><div class="throbber"> </div></div>');
|
||||
if (this.progress.message) {
|
||||
$('.throbber', this.progress.element).after('<div class="message">' + this.progress.message + '</div>')
|
||||
}
|
||||
$(this.element).after(this.progress.element);
|
||||
}
|
||||
|
||||
// Record the build-id.
|
||||
if (this.immutable) {
|
||||
var ahah = this;
|
||||
$.each(form_values, function () {
|
||||
if (this.name == 'form_build_id') {
|
||||
ahah.buildId = this.value;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Modify the request object before it is sent.
|
||||
*/
|
||||
Drupal.ahah.prototype.beforeSend = function (request, options) {
|
||||
if (this.immutable) {
|
||||
request.setRequestHeader('X-Drupal-Accept-Build-Id', '1');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for the form redirection completion.
|
||||
*/
|
||||
Drupal.ahah.prototype.success = function (response, status) {
|
||||
var wrapper = $(this.wrapper);
|
||||
var form = $(this.element).parents('form');
|
||||
// Manually insert HTML into the jQuery object, using $() directly crashes
|
||||
// Safari with long string lengths. http://dev.jquery.com/ticket/1152
|
||||
var new_content = $('<div></div>').html(response.data);
|
||||
|
||||
// Restore the previous action and target to the form.
|
||||
form.attr('action', this.form_action);
|
||||
this.form_target ? form.attr('target', this.form_target) : form.removeAttr('target');
|
||||
this.form_encattr ? form.attr('target', this.form_encattr) : form.removeAttr('encattr');
|
||||
|
||||
// Remove the progress element.
|
||||
if (this.progress.element) {
|
||||
$(this.progress.element).remove();
|
||||
}
|
||||
if (this.progress.object) {
|
||||
this.progress.object.stopMonitoring();
|
||||
}
|
||||
$(this.element).removeClass('progress-disabled').attr('disabled', false);
|
||||
|
||||
// Add the new content to the page.
|
||||
Drupal.freezeHeight();
|
||||
if (this.method == 'replace') {
|
||||
wrapper.empty().append(new_content);
|
||||
}
|
||||
else {
|
||||
wrapper[this.method](new_content);
|
||||
}
|
||||
|
||||
// Immediately hide the new content if we're using any effects.
|
||||
if (this.showEffect != 'show') {
|
||||
new_content.hide();
|
||||
}
|
||||
|
||||
// Determine what effect use and what content will receive the effect, then
|
||||
// show the new content. For browser compatibility, Safari is excluded from
|
||||
// using effects on table rows.
|
||||
if (($.browser.safari && $("tr.ahah-new-content", new_content).size() > 0)) {
|
||||
new_content.show();
|
||||
}
|
||||
else if ($('.ahah-new-content', new_content).size() > 0) {
|
||||
$('.ahah-new-content', new_content).hide();
|
||||
new_content.show();
|
||||
$(".ahah-new-content", new_content)[this.showEffect](this.showSpeed);
|
||||
}
|
||||
else if (this.showEffect != 'show') {
|
||||
new_content[this.showEffect](this.showSpeed);
|
||||
}
|
||||
|
||||
// Attach all javascript behaviors to the new content, if it was successfully
|
||||
// added to the page, this if statement allows #ahah[wrapper] to be optional.
|
||||
if (new_content.parents('html').length > 0) {
|
||||
Drupal.attachBehaviors(new_content);
|
||||
}
|
||||
|
||||
Drupal.unfreezeHeight();
|
||||
};
|
||||
|
||||
/**
|
||||
* Handler for the form redirection error.
|
||||
*/
|
||||
Drupal.ahah.prototype.error = function (response, uri) {
|
||||
alert(Drupal.ahahError(response, uri));
|
||||
// Resore the previous action and target to the form.
|
||||
$(this.element).parent('form').attr( { action: this.form_action, target: this.form_target} );
|
||||
// Remove the progress element.
|
||||
if (this.progress.element) {
|
||||
$(this.progress.element).remove();
|
||||
}
|
||||
if (this.progress.object) {
|
||||
this.progress.object.stopMonitoring();
|
||||
}
|
||||
// Undo hide.
|
||||
$(this.wrapper).show();
|
||||
// Re-enable the element.
|
||||
$(this.element).removeClass('progess-disabled').attr('disabled', false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handler called when the request finishes, whether in failure or success.
|
||||
*/
|
||||
Drupal.ahah.prototype.complete = function (response, status) {
|
||||
// Update form build id if necessary.
|
||||
if (this.immutable) {
|
||||
var newBuildId = response.getResponseHeader('X-Drupal-Build-Id');
|
||||
if (this.buildId && newBuildId && this.buildId != newBuildId) {
|
||||
var $element = $('input[name="form_build_id"][value="' + this.buildId + '"]');
|
||||
$element.val(newBuildId);
|
||||
$element.attr('id', newBuildId);
|
||||
}
|
||||
this.buildId = null;
|
||||
}
|
||||
}
|
BIN
misc/arrow-asc.png
Normal file
After Width: | Height: | Size: 118 B |
BIN
misc/arrow-desc.png
Normal file
After Width: | Height: | Size: 119 B |
307
misc/autocomplete.js
Normal file
|
@ -0,0 +1,307 @@
|
|||
|
||||
/**
|
||||
* Attaches the autocomplete behavior to all required fields
|
||||
*/
|
||||
Drupal.behaviors.autocomplete = function (context) {
|
||||
var acdb = [];
|
||||
$('input.autocomplete:not(.autocomplete-processed)', context).each(function () {
|
||||
var uri = this.value;
|
||||
if (!acdb[uri]) {
|
||||
acdb[uri] = new Drupal.ACDB(uri);
|
||||
}
|
||||
var input = $('#' + this.id.substr(0, this.id.length - 13))
|
||||
.attr('autocomplete', 'OFF')[0];
|
||||
$(input.form).submit(Drupal.autocompleteSubmit);
|
||||
new Drupal.jsAC(input, acdb[uri]);
|
||||
$(this).addClass('autocomplete-processed');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Prevents the form from submitting if the suggestions popup is open
|
||||
* and closes the suggestions popup when doing so.
|
||||
*/
|
||||
Drupal.autocompleteSubmit = function () {
|
||||
return $('#autocomplete').each(function () {
|
||||
this.owner.hidePopup();
|
||||
}).size() == 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* An AutoComplete object
|
||||
*/
|
||||
Drupal.jsAC = function (input, db) {
|
||||
var ac = this;
|
||||
this.input = input;
|
||||
this.db = db;
|
||||
|
||||
$(this.input)
|
||||
.keydown(function (event) { return ac.onkeydown(this, event); })
|
||||
.keyup(function (event) { ac.onkeyup(this, event); })
|
||||
.blur(function () { ac.hidePopup(); ac.db.cancel(); });
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Handler for the "keydown" event
|
||||
*/
|
||||
Drupal.jsAC.prototype.onkeydown = function (input, e) {
|
||||
if (!e) {
|
||||
e = window.event;
|
||||
}
|
||||
switch (e.keyCode) {
|
||||
case 40: // down arrow
|
||||
this.selectDown();
|
||||
return false;
|
||||
case 38: // up arrow
|
||||
this.selectUp();
|
||||
return false;
|
||||
default: // all other keys
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handler for the "keyup" event
|
||||
*/
|
||||
Drupal.jsAC.prototype.onkeyup = function (input, e) {
|
||||
if (!e) {
|
||||
e = window.event;
|
||||
}
|
||||
switch (e.keyCode) {
|
||||
case 16: // shift
|
||||
case 17: // ctrl
|
||||
case 18: // alt
|
||||
case 20: // caps lock
|
||||
case 33: // page up
|
||||
case 34: // page down
|
||||
case 35: // end
|
||||
case 36: // home
|
||||
case 37: // left arrow
|
||||
case 38: // up arrow
|
||||
case 39: // right arrow
|
||||
case 40: // down arrow
|
||||
return true;
|
||||
|
||||
case 9: // tab
|
||||
case 13: // enter
|
||||
case 27: // esc
|
||||
this.hidePopup(e.keyCode);
|
||||
return true;
|
||||
|
||||
default: // all other keys
|
||||
if (input.value.length > 0)
|
||||
this.populatePopup();
|
||||
else
|
||||
this.hidePopup(e.keyCode);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts the currently highlighted suggestion into the autocomplete field
|
||||
*/
|
||||
Drupal.jsAC.prototype.select = function (node) {
|
||||
this.input.value = node.autocompleteValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Highlights the next suggestion
|
||||
*/
|
||||
Drupal.jsAC.prototype.selectDown = function () {
|
||||
if (this.selected && this.selected.nextSibling) {
|
||||
this.highlight(this.selected.nextSibling);
|
||||
}
|
||||
else {
|
||||
var lis = $('li', this.popup);
|
||||
if (lis.size() > 0) {
|
||||
this.highlight(lis.get(0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Highlights the previous suggestion
|
||||
*/
|
||||
Drupal.jsAC.prototype.selectUp = function () {
|
||||
if (this.selected && this.selected.previousSibling) {
|
||||
this.highlight(this.selected.previousSibling);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Highlights a suggestion
|
||||
*/
|
||||
Drupal.jsAC.prototype.highlight = function (node) {
|
||||
if (this.selected) {
|
||||
$(this.selected).removeClass('selected');
|
||||
}
|
||||
$(node).addClass('selected');
|
||||
this.selected = node;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unhighlights a suggestion
|
||||
*/
|
||||
Drupal.jsAC.prototype.unhighlight = function (node) {
|
||||
$(node).removeClass('selected');
|
||||
this.selected = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hides the autocomplete suggestions
|
||||
*/
|
||||
Drupal.jsAC.prototype.hidePopup = function (keycode) {
|
||||
// Select item if the right key or mousebutton was pressed
|
||||
if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
|
||||
this.input.value = this.selected.autocompleteValue;
|
||||
}
|
||||
// Hide popup
|
||||
var popup = this.popup;
|
||||
if (popup) {
|
||||
this.popup = null;
|
||||
$(popup).fadeOut('fast', function() { $(popup).remove(); });
|
||||
}
|
||||
this.selected = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Positions the suggestions popup and starts a search
|
||||
*/
|
||||
Drupal.jsAC.prototype.populatePopup = function () {
|
||||
// Show popup
|
||||
if (this.popup) {
|
||||
$(this.popup).remove();
|
||||
}
|
||||
this.selected = false;
|
||||
this.popup = document.createElement('div');
|
||||
this.popup.id = 'autocomplete';
|
||||
this.popup.owner = this;
|
||||
$(this.popup).css({
|
||||
marginTop: this.input.offsetHeight +'px',
|
||||
width: (this.input.offsetWidth - 4) +'px',
|
||||
display: 'none'
|
||||
});
|
||||
$(this.input).before(this.popup);
|
||||
|
||||
// Do search
|
||||
this.db.owner = this;
|
||||
this.db.search(this.input.value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Fills the suggestion popup with any matches received
|
||||
*/
|
||||
Drupal.jsAC.prototype.found = function (matches) {
|
||||
// If no value in the textfield, do not show the popup.
|
||||
if (!this.input.value.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prepare matches
|
||||
var ul = document.createElement('ul');
|
||||
var ac = this;
|
||||
for (key in matches) {
|
||||
var li = document.createElement('li');
|
||||
$(li)
|
||||
.html('<div>'+ matches[key] +'</div>')
|
||||
.mousedown(function () { ac.select(this); })
|
||||
.mouseover(function () { ac.highlight(this); })
|
||||
.mouseout(function () { ac.unhighlight(this); });
|
||||
li.autocompleteValue = key;
|
||||
$(ul).append(li);
|
||||
}
|
||||
|
||||
// Show popup with matches, if any
|
||||
if (this.popup) {
|
||||
if (ul.childNodes.length > 0) {
|
||||
$(this.popup).empty().append(ul).show();
|
||||
}
|
||||
else {
|
||||
$(this.popup).css({visibility: 'hidden'});
|
||||
this.hidePopup();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.jsAC.prototype.setStatus = function (status) {
|
||||
switch (status) {
|
||||
case 'begin':
|
||||
$(this.input).addClass('throbbing');
|
||||
break;
|
||||
case 'cancel':
|
||||
case 'error':
|
||||
case 'found':
|
||||
$(this.input).removeClass('throbbing');
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An AutoComplete DataBase object
|
||||
*/
|
||||
Drupal.ACDB = function (uri) {
|
||||
this.uri = uri;
|
||||
this.delay = 300;
|
||||
this.cache = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs a cached and delayed search
|
||||
*/
|
||||
Drupal.ACDB.prototype.search = function (searchString) {
|
||||
var db = this;
|
||||
this.searchString = searchString;
|
||||
|
||||
// See if this string needs to be searched for anyway. The pattern ../ is
|
||||
// stripped since it may be misinterpreted by the browser.
|
||||
searchString = searchString.replace(/^\s+|\.{2,}\/|\s+$/g, '');
|
||||
// Skip empty search strings, or search strings ending with a comma, since
|
||||
// that is the separator between search terms.
|
||||
if (searchString.length <= 0 ||
|
||||
searchString.charAt(searchString.length - 1) == ',') {
|
||||
return;
|
||||
}
|
||||
|
||||
// See if this key has been searched for before
|
||||
if (this.cache[searchString]) {
|
||||
return this.owner.found(this.cache[searchString]);
|
||||
}
|
||||
|
||||
// Initiate delayed search
|
||||
if (this.timer) {
|
||||
clearTimeout(this.timer);
|
||||
}
|
||||
this.timer = setTimeout(function() {
|
||||
db.owner.setStatus('begin');
|
||||
|
||||
// Ajax GET request for autocompletion
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: db.uri +'/'+ Drupal.encodeURIComponent(searchString),
|
||||
dataType: 'json',
|
||||
success: function (matches) {
|
||||
if (typeof matches['status'] == 'undefined' || matches['status'] != 0) {
|
||||
db.cache[searchString] = matches;
|
||||
// Verify if these are still the matches the user wants to see
|
||||
if (db.searchString == searchString) {
|
||||
db.owner.found(matches);
|
||||
}
|
||||
db.owner.setStatus('found');
|
||||
}
|
||||
},
|
||||
error: function (xmlhttp) {
|
||||
alert(Drupal.ahahError(xmlhttp, db.uri));
|
||||
}
|
||||
});
|
||||
}, this.delay);
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancels the current autocomplete request
|
||||
*/
|
||||
Drupal.ACDB.prototype.cancel = function() {
|
||||
if (this.owner) this.owner.setStatus('cancel');
|
||||
if (this.timer) clearTimeout(this.timer);
|
||||
this.searchString = '';
|
||||
};
|
37
misc/batch.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
|
||||
/**
|
||||
* Attaches the batch behavior to progress bars.
|
||||
*/
|
||||
Drupal.behaviors.batch = function (context) {
|
||||
// This behavior attaches by ID, so is only valid once on a page.
|
||||
if ($('#progress.batch-processed').size()) {
|
||||
return;
|
||||
}
|
||||
$('#progress', context).addClass('batch-processed').each(function () {
|
||||
var holder = this;
|
||||
var uri = Drupal.settings.batch.uri;
|
||||
var initMessage = Drupal.settings.batch.initMessage;
|
||||
var errorMessage = Drupal.settings.batch.errorMessage;
|
||||
|
||||
// Success: redirect to the summary.
|
||||
var updateCallback = function (progress, status, pb) {
|
||||
if (progress == 100) {
|
||||
pb.stopMonitoring();
|
||||
window.location = uri+'&op=finished';
|
||||
}
|
||||
};
|
||||
|
||||
var errorCallback = function (pb) {
|
||||
var div = document.createElement('p');
|
||||
div.className = 'error';
|
||||
$(div).html(errorMessage);
|
||||
$(holder).prepend(div);
|
||||
$('#wait').hide();
|
||||
};
|
||||
|
||||
var progress = new Drupal.progressBar('updateprogress', updateCallback, "POST", errorCallback);
|
||||
progress.setProgress(-1, initMessage);
|
||||
$(holder).append(progress.element);
|
||||
progress.startMonitoring(uri+'&op=do', 10);
|
||||
});
|
||||
};
|
BIN
misc/blog.png
Normal file
After Width: | Height: | Size: 109 B |
76
misc/collapse.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
|
||||
/**
|
||||
* Toggle the visibility of a fieldset using smooth animations
|
||||
*/
|
||||
Drupal.toggleFieldset = function(fieldset) {
|
||||
if ($(fieldset).is('.collapsed')) {
|
||||
// Action div containers are processed separately because of a IE bug
|
||||
// that alters the default submit button behavior.
|
||||
var content = $('> div:not(.action)', fieldset);
|
||||
$(fieldset).removeClass('collapsed');
|
||||
content.hide();
|
||||
content.slideDown( {
|
||||
duration: 'fast',
|
||||
easing: 'linear',
|
||||
complete: function() {
|
||||
Drupal.collapseScrollIntoView(this.parentNode);
|
||||
this.parentNode.animating = false;
|
||||
$('div.action', fieldset).show();
|
||||
},
|
||||
step: function() {
|
||||
// Scroll the fieldset into view
|
||||
Drupal.collapseScrollIntoView(this.parentNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
$('div.action', fieldset).hide();
|
||||
var content = $('> div:not(.action)', fieldset).slideUp('fast', function() {
|
||||
$(this.parentNode).addClass('collapsed');
|
||||
this.parentNode.animating = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Scroll a given fieldset into view as much as possible.
|
||||
*/
|
||||
Drupal.collapseScrollIntoView = function (node) {
|
||||
var h = self.innerHeight || document.documentElement.clientHeight || $('body')[0].clientHeight || 0;
|
||||
var offset = self.pageYOffset || document.documentElement.scrollTop || $('body')[0].scrollTop || 0;
|
||||
var posY = $(node).offset().top;
|
||||
var fudge = 55;
|
||||
if (posY + node.offsetHeight + fudge > h + offset) {
|
||||
if (node.offsetHeight > h) {
|
||||
window.scrollTo(0, posY);
|
||||
} else {
|
||||
window.scrollTo(0, posY + node.offsetHeight - h + fudge);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.behaviors.collapse = function (context) {
|
||||
$('fieldset.collapsible > legend:not(.collapse-processed)', context).each(function() {
|
||||
var fieldset = $(this.parentNode);
|
||||
// Expand if there are errors inside
|
||||
if ($('input.error, textarea.error, select.error', fieldset).size() > 0) {
|
||||
fieldset.removeClass('collapsed');
|
||||
}
|
||||
|
||||
// Turn the legend into a clickable link and wrap the contents of the fieldset
|
||||
// in a div for easier animation
|
||||
var text = this.innerHTML;
|
||||
$(this).empty().append($('<a href="#">'+ text +'</a>').click(function() {
|
||||
var fieldset = $(this).parents('fieldset:first')[0];
|
||||
// Don't animate multiple times
|
||||
if (!fieldset.animating) {
|
||||
fieldset.animating = true;
|
||||
Drupal.toggleFieldset(fieldset);
|
||||
}
|
||||
return false;
|
||||
}))
|
||||
.after($('<div class="fieldset-wrapper"></div>')
|
||||
.append(fieldset.children(':not(legend):not(.action)')))
|
||||
.addClass('collapse-processed');
|
||||
});
|
||||
};
|
BIN
misc/draggable.png
Normal file
After Width: | Height: | Size: 349 B |
319
misc/drupal.js
Normal file
|
@ -0,0 +1,319 @@
|
|||
|
||||
/**
|
||||
* Override jQuery.fn.init to guard against XSS attacks.
|
||||
*
|
||||
* See http://bugs.jquery.com/ticket/9521
|
||||
*/
|
||||
(function () {
|
||||
var jquery_init = jQuery.fn.init;
|
||||
jQuery.fn.init = function (selector, context, rootjQuery) {
|
||||
// If the string contains a "#" before a "<", treat it as invalid HTML.
|
||||
if (selector && typeof selector === 'string') {
|
||||
var hash_position = selector.indexOf('#');
|
||||
if (hash_position >= 0) {
|
||||
var bracket_position = selector.indexOf('<');
|
||||
if (bracket_position > hash_position) {
|
||||
throw 'Syntax error, unrecognized expression: ' + selector;
|
||||
}
|
||||
}
|
||||
}
|
||||
return jquery_init.call(this, selector, context, rootjQuery);
|
||||
};
|
||||
jQuery.fn.init.prototype = jquery_init.prototype;
|
||||
})();
|
||||
|
||||
var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'themes': {}, 'locale': {} };
|
||||
|
||||
/**
|
||||
* Set the variable that indicates if JavaScript behaviors should be applied
|
||||
*/
|
||||
Drupal.jsEnabled = document.getElementsByTagName && document.createElement && document.createTextNode && document.documentElement && document.getElementById;
|
||||
|
||||
/**
|
||||
* Attach all registered behaviors to a page element.
|
||||
*
|
||||
* Behaviors are event-triggered actions that attach to page elements, enhancing
|
||||
* default non-Javascript UIs. Behaviors are registered in the Drupal.behaviors
|
||||
* object as follows:
|
||||
* @code
|
||||
* Drupal.behaviors.behaviorName = function () {
|
||||
* ...
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* Drupal.attachBehaviors is added below to the jQuery ready event and so
|
||||
* runs on initial page load. Developers implementing AHAH/AJAX in their
|
||||
* solutions should also call this function after new page content has been
|
||||
* loaded, feeding in an element to be processed, in order to attach all
|
||||
* behaviors to the new content.
|
||||
*
|
||||
* Behaviors should use a class in the form behaviorName-processed to ensure
|
||||
* the behavior is attached only once to a given element. (Doing so enables
|
||||
* the reprocessing of given elements, which may be needed on occasion despite
|
||||
* the ability to limit behavior attachment to a particular element.)
|
||||
*
|
||||
* @param context
|
||||
* An element to attach behaviors to. If none is given, the document element
|
||||
* is used.
|
||||
*/
|
||||
Drupal.attachBehaviors = function(context) {
|
||||
context = context || document;
|
||||
if (Drupal.jsEnabled) {
|
||||
// Execute all of them.
|
||||
jQuery.each(Drupal.behaviors, function() {
|
||||
this(context);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode special characters in a plain-text string for display as HTML.
|
||||
*/
|
||||
Drupal.checkPlain = function(str) {
|
||||
str = String(str);
|
||||
var replace = { '&': '&', '"': '"', '<': '<', '>': '>' };
|
||||
for (var character in replace) {
|
||||
var regex = new RegExp(character, 'g');
|
||||
str = str.replace(regex, replace[character]);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
/**
|
||||
* Translate strings to the page language or a given language.
|
||||
*
|
||||
* See the documentation of the server-side t() function for further details.
|
||||
*
|
||||
* @param str
|
||||
* A string containing the English string to translate.
|
||||
* @param args
|
||||
* An object of replacements pairs to make after translation. Incidences
|
||||
* of any key in this array are replaced with the corresponding value.
|
||||
* Based on the first character of the key, the value is escaped and/or themed:
|
||||
* - !variable: inserted as is
|
||||
* - @variable: escape plain text to HTML (Drupal.checkPlain)
|
||||
* - %variable: escape text and theme as a placeholder for user-submitted
|
||||
* content (checkPlain + Drupal.theme('placeholder'))
|
||||
* @return
|
||||
* The translated string.
|
||||
*/
|
||||
Drupal.t = function(str, args) {
|
||||
// Fetch the localized version of the string.
|
||||
if (Drupal.locale.strings && Drupal.locale.strings[str]) {
|
||||
str = Drupal.locale.strings[str];
|
||||
}
|
||||
|
||||
if (args) {
|
||||
// Transform arguments before inserting them
|
||||
for (var key in args) {
|
||||
switch (key.charAt(0)) {
|
||||
// Escaped only
|
||||
case '@':
|
||||
args[key] = Drupal.checkPlain(args[key]);
|
||||
break;
|
||||
// Pass-through
|
||||
case '!':
|
||||
break;
|
||||
// Escaped and placeholder
|
||||
case '%':
|
||||
default:
|
||||
args[key] = Drupal.theme('placeholder', args[key]);
|
||||
break;
|
||||
}
|
||||
str = str.replace(key, args[key]);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
/**
|
||||
* Format a string containing a count of items.
|
||||
*
|
||||
* This function ensures that the string is pluralized correctly. Since Drupal.t() is
|
||||
* called by this function, make sure not to pass already-localized strings to it.
|
||||
*
|
||||
* See the documentation of the server-side format_plural() function for further details.
|
||||
*
|
||||
* @param count
|
||||
* The item count to display.
|
||||
* @param singular
|
||||
* The string for the singular case. Please make sure it is clear this is
|
||||
* singular, to ease translation (e.g. use "1 new comment" instead of "1 new").
|
||||
* Do not use @count in the singular string.
|
||||
* @param plural
|
||||
* The string for the plural case. Please make sure it is clear this is plural,
|
||||
* to ease translation. Use @count in place of the item count, as in "@count
|
||||
* new comments".
|
||||
* @param args
|
||||
* An object of replacements pairs to make after translation. Incidences
|
||||
* of any key in this array are replaced with the corresponding value.
|
||||
* Based on the first character of the key, the value is escaped and/or themed:
|
||||
* - !variable: inserted as is
|
||||
* - @variable: escape plain text to HTML (Drupal.checkPlain)
|
||||
* - %variable: escape text and theme as a placeholder for user-submitted
|
||||
* content (checkPlain + Drupal.theme('placeholder'))
|
||||
* Note that you do not need to include @count in this array.
|
||||
* This replacement is done automatically for the plural case.
|
||||
* @return
|
||||
* A translated string.
|
||||
*/
|
||||
Drupal.formatPlural = function(count, singular, plural, args) {
|
||||
var args = args || {};
|
||||
args['@count'] = count;
|
||||
// Determine the index of the plural form.
|
||||
var index = Drupal.locale.pluralFormula ? Drupal.locale.pluralFormula(args['@count']) : ((args['@count'] == 1) ? 0 : 1);
|
||||
|
||||
if (index == 0) {
|
||||
return Drupal.t(singular, args);
|
||||
}
|
||||
else if (index == 1) {
|
||||
return Drupal.t(plural, args);
|
||||
}
|
||||
else {
|
||||
args['@count['+ index +']'] = args['@count'];
|
||||
delete args['@count'];
|
||||
return Drupal.t(plural.replace('@count', '@count['+ index +']'), args);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate the themed representation of a Drupal object.
|
||||
*
|
||||
* All requests for themed output must go through this function. It examines
|
||||
* the request and routes it to the appropriate theme function. If the current
|
||||
* theme does not provide an override function, the generic theme function is
|
||||
* called.
|
||||
*
|
||||
* For example, to retrieve the HTML that is output by theme_placeholder(text),
|
||||
* call Drupal.theme('placeholder', text).
|
||||
*
|
||||
* @param func
|
||||
* The name of the theme function to call.
|
||||
* @param ...
|
||||
* Additional arguments to pass along to the theme function.
|
||||
* @return
|
||||
* Any data the theme function returns. This could be a plain HTML string,
|
||||
* but also a complex object.
|
||||
*/
|
||||
Drupal.theme = function(func) {
|
||||
for (var i = 1, args = []; i < arguments.length; i++) {
|
||||
args.push(arguments[i]);
|
||||
}
|
||||
|
||||
return (Drupal.theme[func] || Drupal.theme.prototype[func]).apply(this, args);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a JSON response.
|
||||
*
|
||||
* The result is either the JSON object, or an object with 'status' 0 and 'data' an error message.
|
||||
*/
|
||||
Drupal.parseJson = function (data) {
|
||||
if ((data.substring(0, 1) != '{') && (data.substring(0, 1) != '[')) {
|
||||
return { status: 0, data: data.length ? data : Drupal.t('Unspecified error') };
|
||||
}
|
||||
return eval('(' + data + ');');
|
||||
};
|
||||
|
||||
/**
|
||||
* Freeze the current body height (as minimum height). Used to prevent
|
||||
* unnecessary upwards scrolling when doing DOM manipulations.
|
||||
*/
|
||||
Drupal.freezeHeight = function () {
|
||||
Drupal.unfreezeHeight();
|
||||
var div = document.createElement('div');
|
||||
$(div).css({
|
||||
position: 'absolute',
|
||||
top: '0px',
|
||||
left: '0px',
|
||||
width: '1px',
|
||||
height: $('body').css('height')
|
||||
}).attr('id', 'freeze-height');
|
||||
$('body').append(div);
|
||||
};
|
||||
|
||||
/**
|
||||
* Unfreeze the body height
|
||||
*/
|
||||
Drupal.unfreezeHeight = function () {
|
||||
$('#freeze-height').remove();
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper around encodeURIComponent() which avoids Apache quirks (equivalent of
|
||||
* drupal_urlencode() in PHP). This function should only be used on paths, not
|
||||
* on query string arguments.
|
||||
*/
|
||||
Drupal.encodeURIComponent = function (item, uri) {
|
||||
uri = uri || location.href;
|
||||
item = encodeURIComponent(item).replace(/%2F/g, '/');
|
||||
return (uri.indexOf('?q=') != -1) ? item : item.replace(/%26/g, '%2526').replace(/%23/g, '%2523').replace(/\/\//g, '/%252F');
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the text selection in a textarea.
|
||||
*/
|
||||
Drupal.getSelection = function (element) {
|
||||
if (typeof(element.selectionStart) != 'number' && document.selection) {
|
||||
// The current selection
|
||||
var range1 = document.selection.createRange();
|
||||
var range2 = range1.duplicate();
|
||||
// Select all text.
|
||||
range2.moveToElementText(element);
|
||||
// Now move 'dummy' end point to end point of original range.
|
||||
range2.setEndPoint('EndToEnd', range1);
|
||||
// Now we can calculate start and end points.
|
||||
var start = range2.text.length - range1.text.length;
|
||||
var end = start + range1.text.length;
|
||||
return { 'start': start, 'end': end };
|
||||
}
|
||||
return { 'start': element.selectionStart, 'end': element.selectionEnd };
|
||||
};
|
||||
|
||||
/**
|
||||
* Build an error message from ahah response.
|
||||
*/
|
||||
Drupal.ahahError = function(xmlhttp, uri) {
|
||||
if (xmlhttp.status == 200) {
|
||||
if (jQuery.trim($(xmlhttp.responseText).text())) {
|
||||
var message = Drupal.t("An error occurred. \n@uri\n@text", {'@uri': uri, '@text': xmlhttp.responseText });
|
||||
}
|
||||
else {
|
||||
var message = Drupal.t("An error occurred. \n@uri\n(no information available).", {'@uri': uri, '@text': xmlhttp.responseText });
|
||||
}
|
||||
}
|
||||
else {
|
||||
var message = Drupal.t("An HTTP error @status occurred. \n@uri", {'@uri': uri, '@status': xmlhttp.status });
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
// Global Killswitch on the <html> element
|
||||
if (Drupal.jsEnabled) {
|
||||
// Global Killswitch on the <html> element
|
||||
$(document.documentElement).addClass('js');
|
||||
// 'js enabled' cookie
|
||||
document.cookie = 'has_js=1; path=/';
|
||||
// Attach all behaviors.
|
||||
$(document).ready(function() {
|
||||
Drupal.attachBehaviors(this);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The default themes.
|
||||
*/
|
||||
Drupal.theme.prototype = {
|
||||
|
||||
/**
|
||||
* Formats text for emphasized display in a placeholder inside a sentence.
|
||||
*
|
||||
* @param str
|
||||
* The text to format (plain-text).
|
||||
* @return
|
||||
* The formatted text (html).
|
||||
*/
|
||||
placeholder: function(str) {
|
||||
return '<em>' + Drupal.checkPlain(str) + '</em>';
|
||||
}
|
||||
};
|
BIN
misc/druplicon.png
Normal file
After Width: | Height: | Size: 4 KiB |
34
misc/farbtastic/farbtastic.css
Normal file
|
@ -0,0 +1,34 @@
|
|||
|
||||
.farbtastic {
|
||||
position: relative;
|
||||
}
|
||||
.farbtastic * {
|
||||
position: absolute;
|
||||
cursor: crosshair;
|
||||
}
|
||||
.farbtastic, .farbtastic .wheel {
|
||||
width: 195px;
|
||||
height: 195px;
|
||||
}
|
||||
.farbtastic .color, .farbtastic .overlay {
|
||||
top: 47px;
|
||||
left: 47px;
|
||||
width: 101px;
|
||||
height: 101px;
|
||||
}
|
||||
.farbtastic .wheel {
|
||||
background: url(wheel.png) no-repeat;
|
||||
width: 195px;
|
||||
height: 195px;
|
||||
}
|
||||
.farbtastic .overlay {
|
||||
background: url(mask.png) no-repeat;
|
||||
}
|
||||
.farbtastic .marker {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
margin: -8px 0 0 -8px;
|
||||
overflow: hidden;
|
||||
background: url(marker.png) no-repeat;
|
||||
}
|
||||
|
314
misc/farbtastic/farbtastic.js
Normal file
|
@ -0,0 +1,314 @@
|
|||
// Farbtastic 1.2
|
||||
|
||||
jQuery.fn.farbtastic = function (callback) {
|
||||
$.farbtastic(this, callback);
|
||||
return this;
|
||||
};
|
||||
|
||||
jQuery.farbtastic = function (container, callback) {
|
||||
var container = $(container).get(0);
|
||||
return container.farbtastic || (container.farbtastic = new jQuery._farbtastic(container, callback));
|
||||
};
|
||||
|
||||
jQuery._farbtastic = function (container, callback) {
|
||||
// Store farbtastic object
|
||||
var fb = this;
|
||||
|
||||
// Insert markup
|
||||
$(container).html('<div class="farbtastic"><div class="color"></div><div class="wheel"></div><div class="overlay"></div><div class="h-marker marker"></div><div class="sl-marker marker"></div></div>');
|
||||
var e = $('.farbtastic', container);
|
||||
fb.wheel = $('.wheel', container).get(0);
|
||||
// Dimensions
|
||||
fb.radius = 84;
|
||||
fb.square = 100;
|
||||
fb.width = 194;
|
||||
|
||||
// Fix background PNGs in IE6
|
||||
if (navigator.appVersion.match(/MSIE [0-6]\./)) {
|
||||
$('*', e).each(function () {
|
||||
if (this.currentStyle.backgroundImage != 'none') {
|
||||
var image = this.currentStyle.backgroundImage;
|
||||
image = this.currentStyle.backgroundImage.substring(5, image.length - 2);
|
||||
$(this).css({
|
||||
'backgroundImage': 'none',
|
||||
'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Link to the given element(s) or callback.
|
||||
*/
|
||||
fb.linkTo = function (callback) {
|
||||
// Unbind previous nodes
|
||||
if (typeof fb.callback == 'object') {
|
||||
$(fb.callback).unbind('keyup', fb.updateValue);
|
||||
}
|
||||
|
||||
// Reset color
|
||||
fb.color = null;
|
||||
|
||||
// Bind callback or elements
|
||||
if (typeof callback == 'function') {
|
||||
fb.callback = callback;
|
||||
}
|
||||
else if (typeof callback == 'object' || typeof callback == 'string') {
|
||||
fb.callback = $(callback);
|
||||
fb.callback.bind('keyup', fb.updateValue);
|
||||
if (fb.callback.get(0).value) {
|
||||
fb.setColor(fb.callback.get(0).value);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
fb.updateValue = function (event) {
|
||||
if (this.value && this.value != fb.color) {
|
||||
fb.setColor(this.value);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Change color with HTML syntax #123456
|
||||
*/
|
||||
fb.setColor = function (color) {
|
||||
var unpack = fb.unpack(color);
|
||||
if (fb.color != color && unpack) {
|
||||
fb.color = color;
|
||||
fb.rgb = unpack;
|
||||
fb.hsl = fb.RGBToHSL(fb.rgb);
|
||||
fb.updateDisplay();
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Change color with HSL triplet [0..1, 0..1, 0..1]
|
||||
*/
|
||||
fb.setHSL = function (hsl) {
|
||||
fb.hsl = hsl;
|
||||
fb.rgb = fb.HSLToRGB(hsl);
|
||||
fb.color = fb.pack(fb.rgb);
|
||||
fb.updateDisplay();
|
||||
return this;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Retrieve the coordinates of the given event relative to the center
|
||||
* of the widget.
|
||||
*/
|
||||
fb.widgetCoords = function (event) {
|
||||
var x, y;
|
||||
var el = event.target || event.srcElement;
|
||||
var reference = fb.wheel;
|
||||
|
||||
// If the offset from the relative element is undefined calculate it.
|
||||
if ( typeof event.offsetX == 'undefined' && typeof event.offsetY == 'undefined' ) {
|
||||
var offset = $(event.target).offset(false);
|
||||
event.offsetX = event.pageX - offset.left;
|
||||
event.offsetY = event.pageY - offset.top;
|
||||
}
|
||||
|
||||
// Use offset coordinates and find common offsetParent
|
||||
var pos = { x: event.offsetX, y: event.offsetY };
|
||||
|
||||
// Send the coordinates upwards through the offsetParent chain.
|
||||
var e = el;
|
||||
while (e) {
|
||||
e.mouseX = pos.x;
|
||||
e.mouseY = pos.y;
|
||||
pos.x += e.offsetLeft;
|
||||
pos.y += e.offsetTop;
|
||||
e = e.offsetParent;
|
||||
}
|
||||
|
||||
// Look for the coordinates starting from the wheel widget.
|
||||
var e = reference;
|
||||
var offset = { x: 0, y: 0 };
|
||||
while (e) {
|
||||
if (typeof e.mouseX != 'undefined') {
|
||||
x = e.mouseX - offset.x;
|
||||
y = e.mouseY - offset.y;
|
||||
break;
|
||||
}
|
||||
offset.x += e.offsetLeft;
|
||||
offset.y += e.offsetTop;
|
||||
e = e.offsetParent;
|
||||
}
|
||||
|
||||
// Reset stored coordinates
|
||||
e = el;
|
||||
while (e) {
|
||||
e.mouseX = undefined;
|
||||
e.mouseY = undefined;
|
||||
e = e.offsetParent;
|
||||
}
|
||||
|
||||
// Subtract distance to middle
|
||||
return { x: x - fb.width / 2, y: y - fb.width / 2 };
|
||||
};
|
||||
|
||||
/**
|
||||
* Mousedown handler
|
||||
*/
|
||||
fb.mousedown = function (event) {
|
||||
// Capture mouse
|
||||
if (!document.dragging) {
|
||||
$(document).bind('mousemove', fb.mousemove).bind('mouseup', fb.mouseup);
|
||||
document.dragging = true;
|
||||
}
|
||||
|
||||
// Check which area is being dragged
|
||||
var pos = fb.widgetCoords(event);
|
||||
fb.circleDrag = Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > fb.square;
|
||||
|
||||
// Process
|
||||
fb.mousemove(event);
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mousemove handler
|
||||
*/
|
||||
fb.mousemove = function (event) {
|
||||
// Get coordinates relative to color picker center
|
||||
var pos = fb.widgetCoords(event);
|
||||
|
||||
// Set new HSL parameters
|
||||
if (fb.circleDrag) {
|
||||
var hue = Math.atan2(pos.x, -pos.y) / 6.28;
|
||||
if (hue < 0) hue += 1;
|
||||
fb.setHSL([hue, fb.hsl[1], fb.hsl[2]]);
|
||||
}
|
||||
else {
|
||||
var sat = Math.max(0, Math.min(1, -(pos.x / fb.square) + .5));
|
||||
var lum = Math.max(0, Math.min(1, -(pos.y / fb.square) + .5));
|
||||
fb.setHSL([fb.hsl[0], sat, lum]);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mouseup handler
|
||||
*/
|
||||
fb.mouseup = function () {
|
||||
// Uncapture mouse
|
||||
$(document).unbind('mousemove', fb.mousemove);
|
||||
$(document).unbind('mouseup', fb.mouseup);
|
||||
document.dragging = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the markers and styles
|
||||
*/
|
||||
fb.updateDisplay = function () {
|
||||
// Markers
|
||||
var angle = fb.hsl[0] * 6.28;
|
||||
$('.h-marker', e).css({
|
||||
left: Math.round(Math.sin(angle) * fb.radius + fb.width / 2) + 'px',
|
||||
top: Math.round(-Math.cos(angle) * fb.radius + fb.width / 2) + 'px'
|
||||
});
|
||||
|
||||
$('.sl-marker', e).css({
|
||||
left: Math.round(fb.square * (.5 - fb.hsl[1]) + fb.width / 2) + 'px',
|
||||
top: Math.round(fb.square * (.5 - fb.hsl[2]) + fb.width / 2) + 'px'
|
||||
});
|
||||
|
||||
// Saturation/Luminance gradient
|
||||
$('.color', e).css('backgroundColor', fb.pack(fb.HSLToRGB([fb.hsl[0], 1, 0.5])));
|
||||
|
||||
// Linked elements or callback
|
||||
if (typeof fb.callback == 'object') {
|
||||
// Set background/foreground color
|
||||
$(fb.callback).css({
|
||||
backgroundColor: fb.color,
|
||||
color: fb.hsl[2] > 0.5 ? '#000' : '#fff'
|
||||
});
|
||||
|
||||
// Change linked value
|
||||
$(fb.callback).each(function() {
|
||||
if (this.value && this.value != fb.color) {
|
||||
this.value = fb.color;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (typeof fb.callback == 'function') {
|
||||
fb.callback.call(fb, fb.color);
|
||||
}
|
||||
};
|
||||
|
||||
/* Various color utility functions */
|
||||
fb.pack = function (rgb) {
|
||||
var r = Math.round(rgb[0] * 255);
|
||||
var g = Math.round(rgb[1] * 255);
|
||||
var b = Math.round(rgb[2] * 255);
|
||||
return '#' + (r < 16 ? '0' : '') + r.toString(16) +
|
||||
(g < 16 ? '0' : '') + g.toString(16) +
|
||||
(b < 16 ? '0' : '') + b.toString(16);
|
||||
};
|
||||
|
||||
fb.unpack = function (color) {
|
||||
if (color.length == 7) {
|
||||
return [parseInt('0x' + color.substring(1, 3)) / 255,
|
||||
parseInt('0x' + color.substring(3, 5)) / 255,
|
||||
parseInt('0x' + color.substring(5, 7)) / 255];
|
||||
}
|
||||
else if (color.length == 4) {
|
||||
return [parseInt('0x' + color.substring(1, 2)) / 15,
|
||||
parseInt('0x' + color.substring(2, 3)) / 15,
|
||||
parseInt('0x' + color.substring(3, 4)) / 15];
|
||||
}
|
||||
};
|
||||
|
||||
fb.HSLToRGB = function (hsl) {
|
||||
var m1, m2, r, g, b;
|
||||
var h = hsl[0], s = hsl[1], l = hsl[2];
|
||||
m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s;
|
||||
m1 = l * 2 - m2;
|
||||
return [this.hueToRGB(m1, m2, h+0.33333),
|
||||
this.hueToRGB(m1, m2, h),
|
||||
this.hueToRGB(m1, m2, h-0.33333)];
|
||||
};
|
||||
|
||||
fb.hueToRGB = function (m1, m2, h) {
|
||||
h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h);
|
||||
if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
|
||||
if (h * 2 < 1) return m2;
|
||||
if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6;
|
||||
return m1;
|
||||
};
|
||||
|
||||
fb.RGBToHSL = function (rgb) {
|
||||
var min, max, delta, h, s, l;
|
||||
var r = rgb[0], g = rgb[1], b = rgb[2];
|
||||
min = Math.min(r, Math.min(g, b));
|
||||
max = Math.max(r, Math.max(g, b));
|
||||
delta = max - min;
|
||||
l = (min + max) / 2;
|
||||
s = 0;
|
||||
if (l > 0 && l < 1) {
|
||||
s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));
|
||||
}
|
||||
h = 0;
|
||||
if (delta > 0) {
|
||||
if (max == r && max != g) h += (g - b) / delta;
|
||||
if (max == g && max != b) h += (2 + (b - r) / delta);
|
||||
if (max == b && max != r) h += (4 + (r - g) / delta);
|
||||
h /= 6;
|
||||
}
|
||||
return [h, s, l];
|
||||
};
|
||||
|
||||
// Install mousedown handler (the others are set on the document on-demand)
|
||||
$('*', e).mousedown(fb.mousedown);
|
||||
|
||||
// Init color
|
||||
fb.setColor('#000000');
|
||||
|
||||
// Set linked elements/callback
|
||||
if (callback) {
|
||||
fb.linkTo(callback);
|
||||
}
|
||||
};
|
BIN
misc/farbtastic/marker.png
Normal file
After Width: | Height: | Size: 652 B |
BIN
misc/farbtastic/mask.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
misc/farbtastic/wheel.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
misc/favicon.ico
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
misc/feed.png
Normal file
After Width: | Height: | Size: 764 B |
9
misc/form.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
|
||||
Drupal.behaviors.multiselectSelector = function() {
|
||||
// Automatically selects the right radio button in a multiselect control.
|
||||
$('.multiselect select:not(.multiselectSelector-processed)')
|
||||
.addClass('multiselectSelector-processed').change(function() {
|
||||
$('.multiselect input:radio[value="'+ this.id.substr(5) +'"]')
|
||||
.attr('checked', true);
|
||||
});
|
||||
};
|
BIN
misc/forum-closed.png
Normal file
After Width: | Height: | Size: 200 B |
BIN
misc/forum-default.png
Normal file
After Width: | Height: | Size: 181 B |
BIN
misc/forum-hot-new.png
Normal file
After Width: | Height: | Size: 237 B |
BIN
misc/forum-hot.png
Normal file
After Width: | Height: | Size: 229 B |
BIN
misc/forum-new.png
Normal file
After Width: | Height: | Size: 175 B |
BIN
misc/forum-sticky.png
Normal file
After Width: | Height: | Size: 329 B |
BIN
misc/grippie.png
Normal file
After Width: | Height: | Size: 162 B |
12
misc/jquery.form.js
Normal file
12
misc/jquery.js
vendored
Normal file
BIN
misc/menu-collapsed-rtl.png
Normal file
After Width: | Height: | Size: 130 B |
BIN
misc/menu-collapsed.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
misc/menu-expanded.png
Normal file
After Width: | Height: | Size: 106 B |
BIN
misc/menu-leaf.png
Normal file
After Width: | Height: | Size: 194 B |
BIN
misc/powered-black-135x42.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
misc/powered-black-80x15.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
misc/powered-black-88x31.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
misc/powered-blue-135x42.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
misc/powered-blue-80x15.png
Normal file
After Width: | Height: | Size: 1,011 B |
BIN
misc/powered-blue-88x31.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
misc/powered-gray-135x42.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
misc/powered-gray-80x15.png
Normal file
After Width: | Height: | Size: 758 B |
BIN
misc/powered-gray-88x31.png
Normal file
After Width: | Height: | Size: 2 KiB |
7
misc/print-rtl.css
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
body {
|
||||
direction: rtl;
|
||||
}
|
||||
th {
|
||||
text-align: right;
|
||||
}
|
25
misc/print.css
Normal file
|
@ -0,0 +1,25 @@
|
|||
|
||||
body {
|
||||
margin: 1em;
|
||||
background-color: #fff;
|
||||
}
|
||||
th {
|
||||
text-align: left; /* LTR */
|
||||
color: #006;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
tr.odd {
|
||||
background-color: #ddd;
|
||||
}
|
||||
tr.even {
|
||||
background-color: #fff;
|
||||
}
|
||||
td {
|
||||
padding: 5px;
|
||||
}
|
||||
#menu {
|
||||
visibility: hidden;
|
||||
}
|
||||
#main {
|
||||
margin: 1em;
|
||||
}
|
BIN
misc/progress.gif
Normal file
After Width: | Height: | Size: 790 B |
106
misc/progress.js
Normal file
|
@ -0,0 +1,106 @@
|
|||
|
||||
/**
|
||||
* A progressbar object. Initialized with the given id. Must be inserted into
|
||||
* the DOM afterwards through progressBar.element.
|
||||
*
|
||||
* method is the function which will perform the HTTP request to get the
|
||||
* progress bar state. Either "GET" or "POST".
|
||||
*
|
||||
* e.g. pb = new progressBar('myProgressBar');
|
||||
* some_element.appendChild(pb.element);
|
||||
*/
|
||||
Drupal.progressBar = function (id, updateCallback, method, errorCallback) {
|
||||
var pb = this;
|
||||
this.id = id;
|
||||
this.method = method || "GET";
|
||||
this.updateCallback = updateCallback;
|
||||
this.errorCallback = errorCallback;
|
||||
|
||||
this.element = document.createElement('div');
|
||||
this.element.id = id;
|
||||
this.element.className = 'progress';
|
||||
$(this.element).html('<div class="bar"><div class="filled"></div></div>'+
|
||||
'<div class="percentage"></div>'+
|
||||
'<div class="message"> </div>');
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the percentage and status message for the progressbar.
|
||||
*/
|
||||
Drupal.progressBar.prototype.setProgress = function (percentage, message) {
|
||||
if (percentage >= 0 && percentage <= 100) {
|
||||
$('div.filled', this.element).css('width', percentage +'%');
|
||||
$('div.percentage', this.element).html(percentage +'%');
|
||||
}
|
||||
$('div.message', this.element).html(message);
|
||||
if (this.updateCallback) {
|
||||
this.updateCallback(percentage, message, this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Start monitoring progress via Ajax.
|
||||
*/
|
||||
Drupal.progressBar.prototype.startMonitoring = function (uri, delay) {
|
||||
this.delay = delay;
|
||||
this.uri = uri;
|
||||
this.sendPing();
|
||||
};
|
||||
|
||||
/**
|
||||
* Stop monitoring progress via Ajax.
|
||||
*/
|
||||
Drupal.progressBar.prototype.stopMonitoring = function () {
|
||||
clearTimeout(this.timer);
|
||||
// This allows monitoring to be stopped from within the callback
|
||||
this.uri = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request progress data from server.
|
||||
*/
|
||||
Drupal.progressBar.prototype.sendPing = function () {
|
||||
if (this.timer) {
|
||||
clearTimeout(this.timer);
|
||||
}
|
||||
if (this.uri) {
|
||||
var pb = this;
|
||||
// When doing a post request, you need non-null data. Otherwise a
|
||||
// HTTP 411 or HTTP 406 (with Apache mod_security) error may result.
|
||||
$.ajax({
|
||||
type: this.method,
|
||||
url: this.uri,
|
||||
data: '',
|
||||
dataType: 'json',
|
||||
success: function (progress) {
|
||||
// Display errors
|
||||
if (progress.status == 0) {
|
||||
pb.displayError(progress.data);
|
||||
return;
|
||||
}
|
||||
// Update display
|
||||
pb.setProgress(progress.percentage, progress.message);
|
||||
// Schedule next timer
|
||||
pb.timer = setTimeout(function() { pb.sendPing(); }, pb.delay);
|
||||
},
|
||||
error: function (xmlhttp) {
|
||||
pb.displayError(Drupal.ahahError(xmlhttp, pb.uri));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Display errors on the page.
|
||||
*/
|
||||
Drupal.progressBar.prototype.displayError = function (string) {
|
||||
var error = document.createElement('div');
|
||||
error.className = 'error';
|
||||
error.innerHTML = string;
|
||||
|
||||
$(this.element).before(error).hide();
|
||||
|
||||
if (this.errorCallback) {
|
||||
this.errorCallback(this);
|
||||
}
|
||||
};
|
1099
misc/tabledrag.js
Normal file
116
misc/tableheader.js
Normal file
|
@ -0,0 +1,116 @@
|
|||
|
||||
Drupal.tableHeaderDoScroll = function() {
|
||||
if (typeof(Drupal.tableHeaderOnScroll)=='function') {
|
||||
Drupal.tableHeaderOnScroll();
|
||||
}
|
||||
};
|
||||
|
||||
Drupal.behaviors.tableHeader = function (context) {
|
||||
// This breaks in anything less than IE 7. Prevent it from running.
|
||||
if (jQuery.browser.msie && parseInt(jQuery.browser.version, 10) < 7) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep track of all cloned table headers.
|
||||
var headers = [];
|
||||
|
||||
$('table.sticky-enabled thead:not(.tableHeader-processed)', context).each(function () {
|
||||
// Clone thead so it inherits original jQuery properties.
|
||||
var headerClone = $(this).clone(true).insertBefore(this.parentNode).wrap('<table class="sticky-header"></table>').parent().css({
|
||||
position: 'fixed',
|
||||
top: '0px'
|
||||
});
|
||||
|
||||
headerClone = $(headerClone)[0];
|
||||
headers.push(headerClone);
|
||||
|
||||
// Store parent table.
|
||||
var table = $(this).parent('table')[0];
|
||||
headerClone.table = table;
|
||||
// Finish initialzing header positioning.
|
||||
tracker(headerClone);
|
||||
|
||||
$(table).addClass('sticky-table');
|
||||
$(this).addClass('tableHeader-processed');
|
||||
});
|
||||
|
||||
// Define the anchor holding var.
|
||||
var prevAnchor = '';
|
||||
|
||||
// Track positioning and visibility.
|
||||
function tracker(e) {
|
||||
// Save positioning data.
|
||||
var viewHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
|
||||
if (e.viewHeight != viewHeight) {
|
||||
e.viewHeight = viewHeight;
|
||||
e.vPosition = $(e.table).offset().top - 4;
|
||||
e.hPosition = $(e.table).offset().left;
|
||||
e.vLength = e.table.clientHeight - 100;
|
||||
// Resize header and its cell widths.
|
||||
var parentCell = $('th', e.table);
|
||||
$('th', e).each(function(index) {
|
||||
var cellWidth = parentCell.eq(index).css('width');
|
||||
// Exception for IE7.
|
||||
if (cellWidth == 'auto') {
|
||||
cellWidth = parentCell.get(index).clientWidth +'px';
|
||||
}
|
||||
$(this).css('width', cellWidth);
|
||||
});
|
||||
$(e).css('width', $(e.table).css('width'));
|
||||
}
|
||||
|
||||
// Track horizontal positioning relative to the viewport and set visibility.
|
||||
var hScroll = document.documentElement.scrollLeft || document.body.scrollLeft;
|
||||
var vOffset = (document.documentElement.scrollTop || document.body.scrollTop) - e.vPosition;
|
||||
var visState = (vOffset > 0 && vOffset < e.vLength) ? 'visible' : 'hidden';
|
||||
$(e).css({left: -hScroll + e.hPosition +'px', visibility: visState});
|
||||
|
||||
// Check the previous anchor to see if we need to scroll to make room for the header.
|
||||
// Get the height of the header table and scroll up that amount.
|
||||
if (prevAnchor != location.hash) {
|
||||
if (location.hash != '') {
|
||||
var offset = $(document).find('td' + location.hash).offset();
|
||||
if (offset) {
|
||||
var top = offset.top;
|
||||
var scrollLocation = top - $(e).height();
|
||||
$('body, html').scrollTop(scrollLocation);
|
||||
}
|
||||
}
|
||||
prevAnchor = location.hash;
|
||||
}
|
||||
}
|
||||
|
||||
// Only attach to scrollbars once, even if Drupal.attachBehaviors is called
|
||||
// multiple times.
|
||||
if (!$('body').hasClass('tableHeader-processed')) {
|
||||
$('body').addClass('tableHeader-processed');
|
||||
$(window).scroll(Drupal.tableHeaderDoScroll);
|
||||
$(document.documentElement).scroll(Drupal.tableHeaderDoScroll);
|
||||
}
|
||||
|
||||
// Track scrolling.
|
||||
Drupal.tableHeaderOnScroll = function() {
|
||||
$(headers).each(function () {
|
||||
tracker(this);
|
||||
});
|
||||
};
|
||||
|
||||
// Track resizing.
|
||||
var time = null;
|
||||
var resize = function () {
|
||||
// Ensure minimum time between adjustments.
|
||||
if (time) {
|
||||
return;
|
||||
}
|
||||
time = setTimeout(function () {
|
||||
$('table.sticky-header').each(function () {
|
||||
// Force cell width calculation.
|
||||
this.viewHeight = 0;
|
||||
tracker(this);
|
||||
});
|
||||
// Reset timer
|
||||
time = null;
|
||||
}, 250);
|
||||
};
|
||||
$(window).resize(resize);
|
||||
};
|
86
misc/tableselect.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
|
||||
Drupal.behaviors.tableSelect = function (context) {
|
||||
$('form table:has(th.select-all):not(.tableSelect-processed)', context).each(Drupal.tableSelect);
|
||||
};
|
||||
|
||||
Drupal.tableSelect = function() {
|
||||
// Do not add a "Select all" checkbox if there are no rows with checkboxes in the table
|
||||
if ($('td input:checkbox', this).size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep track of the table, which checkbox is checked and alias the settings.
|
||||
var table = this, checkboxes, lastChecked;
|
||||
var strings = { 'selectAll': Drupal.t('Select all rows in this table'), 'selectNone': Drupal.t('Deselect all rows in this table') };
|
||||
var updateSelectAll = function(state) {
|
||||
$('th.select-all input:checkbox', table).each(function() {
|
||||
$(this).attr('title', state ? strings.selectNone : strings.selectAll);
|
||||
this.checked = state;
|
||||
});
|
||||
};
|
||||
|
||||
// Find all <th> with class select-all, and insert the check all checkbox.
|
||||
$('th.select-all', table).prepend($('<input type="checkbox" class="form-checkbox" />').attr('title', strings.selectAll)).click(function(event) {
|
||||
if ($(event.target).is('input:checkbox')) {
|
||||
// Loop through all checkboxes and set their state to the select all checkbox' state.
|
||||
checkboxes.each(function() {
|
||||
this.checked = event.target.checked;
|
||||
// Either add or remove the selected class based on the state of the check all checkbox.
|
||||
$(this).parents('tr:first')[ this.checked ? 'addClass' : 'removeClass' ]('selected');
|
||||
});
|
||||
// Update the title and the state of the check all box.
|
||||
updateSelectAll(event.target.checked);
|
||||
}
|
||||
});
|
||||
|
||||
// For each of the checkboxes within the table.
|
||||
checkboxes = $('td input:checkbox', table).click(function(e) {
|
||||
// Either add or remove the selected class based on the state of the check all checkbox.
|
||||
$(this).parents('tr:first')[ this.checked ? 'addClass' : 'removeClass' ]('selected');
|
||||
|
||||
// If this is a shift click, we need to highlight everything in the range.
|
||||
// Also make sure that we are actually checking checkboxes over a range and
|
||||
// that a checkbox has been checked or unchecked before.
|
||||
if (e.shiftKey && lastChecked && lastChecked != e.target) {
|
||||
// We use the checkbox's parent TR to do our range searching.
|
||||
Drupal.tableSelectRange($(e.target).parents('tr')[0], $(lastChecked).parents('tr')[0], e.target.checked);
|
||||
}
|
||||
|
||||
// If all checkboxes are checked, make sure the select-all one is checked too, otherwise keep unchecked.
|
||||
updateSelectAll((checkboxes.length == $(checkboxes).filter(':checked').length));
|
||||
|
||||
// Keep track of the last checked checkbox.
|
||||
lastChecked = e.target;
|
||||
});
|
||||
$(this).addClass('tableSelect-processed');
|
||||
};
|
||||
|
||||
Drupal.tableSelectRange = function(from, to, state) {
|
||||
// We determine the looping mode based on the order of from and to.
|
||||
var mode = from.rowIndex > to.rowIndex ? 'previousSibling' : 'nextSibling';
|
||||
|
||||
// Traverse through the sibling nodes.
|
||||
for (var i = from[mode]; i; i = i[mode]) {
|
||||
// Make sure that we're only dealing with elements.
|
||||
if (i.nodeType != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Either add or remove the selected class based on the state of the target checkbox.
|
||||
$(i)[ state ? 'addClass' : 'removeClass' ]('selected');
|
||||
$('input:checkbox', i).each(function() {
|
||||
this.checked = state;
|
||||
});
|
||||
|
||||
if (to.nodeType) {
|
||||
// If we are at the end of the range, stop.
|
||||
if (i == to) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// A faster alternative to doing $(i).filter(to).length.
|
||||
else if (jQuery.filter(to, [i]).r.length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
95
misc/teaser.js
Normal file
|
@ -0,0 +1,95 @@
|
|||
|
||||
/**
|
||||
* Auto-attach for teaser behavior.
|
||||
*
|
||||
* Note: depends on resizable textareas.
|
||||
*/
|
||||
Drupal.behaviors.teaser = function(context) {
|
||||
// This breaks in Konqueror. Prevent it from running.
|
||||
if (/KDE/.test(navigator.vendor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('textarea.teaser:not(.teaser-processed)', context).each(function() {
|
||||
var teaser = $(this).addClass('teaser-processed');
|
||||
|
||||
// Move teaser textarea before body, and remove its form-item wrapper.
|
||||
var body = $('#'+ Drupal.settings.teaser[this.id]);
|
||||
var checkbox = $('#'+ Drupal.settings.teaserCheckbox[this.id]).parent();
|
||||
var checked = $(checkbox).children('input').attr('checked') ? true : false;
|
||||
var parent = teaser[0].parentNode;
|
||||
$(body).before(teaser);
|
||||
$(parent).remove();
|
||||
|
||||
function trim(text) {
|
||||
return text.replace(/^\s+/g, '').replace(/\s+$/g, '');
|
||||
}
|
||||
|
||||
// Join the teaser back to the body.
|
||||
function join_teaser() {
|
||||
if (teaser.val()) {
|
||||
body.val(trim(teaser.val()) +'\r\n\r\n'+ trim(body.val()));
|
||||
}
|
||||
// Empty, hide and disable teaser.
|
||||
teaser[0].value = '';
|
||||
$(teaser).attr('disabled', 'disabled');
|
||||
$(teaser).parent().slideUp('fast');
|
||||
// Change label.
|
||||
$(this).val(Drupal.t('Split summary at cursor'));
|
||||
// Hide separate teaser checkbox.
|
||||
$(checkbox).hide();
|
||||
// Force a hidden checkbox to be checked (to ensure that the body is
|
||||
// correctly processed on form submit when teaser/body are in joined
|
||||
// state), and remember the current checked status.
|
||||
checked = $(checkbox).children('input').attr('checked') ? true : false;
|
||||
$(checkbox).children('input').attr('checked', true);
|
||||
}
|
||||
|
||||
// Split the teaser from the body.
|
||||
function split_teaser() {
|
||||
body[0].focus();
|
||||
var selection = Drupal.getSelection(body[0]);
|
||||
var split = selection.start;
|
||||
var text = body.val();
|
||||
|
||||
// Note: using val() fails sometimes. jQuery bug?
|
||||
teaser[0].value = trim(text.slice(0, split));
|
||||
body[0].value = trim(text.slice(split));
|
||||
// Reveal and enable teaser
|
||||
$(teaser).attr('disabled', '');
|
||||
$(teaser).parent().slideDown('fast');
|
||||
// Change label
|
||||
$(this).val(Drupal.t('Join summary'));
|
||||
// Show separate teaser checkbox, restore checked value.
|
||||
$(checkbox).show().children('input').attr('checked', checked);
|
||||
}
|
||||
|
||||
// Add split/join button.
|
||||
var button = $('<div class="teaser-button-wrapper"><input type="button" class="teaser-button" /></div>');
|
||||
var include = $('#'+ this.id.substring(0, this.id.length - 2) +'include');
|
||||
$(include).parent().parent().before(button);
|
||||
|
||||
// Extract the teaser from the body, if set. Otherwise, stay in joined mode.
|
||||
var text = body.val().split('<!--break-->');
|
||||
if (text.length >= 2) {
|
||||
teaser[0].value = trim(text.shift());
|
||||
body[0].value = trim(text.join('<!--break-->'));
|
||||
$(teaser).attr('disabled', '');
|
||||
$('input', button).val(Drupal.t('Join summary')).toggle(join_teaser, split_teaser);
|
||||
}
|
||||
else {
|
||||
$('input', button).val(Drupal.t('Split summary at cursor')).toggle(split_teaser, join_teaser);
|
||||
$(checkbox).hide().children('input').attr('checked', true);
|
||||
}
|
||||
|
||||
// Make sure that textarea.js has done its magic to ensure proper visibility state.
|
||||
if (Drupal.behaviors.textarea && teaser.is(('.form-textarea:not(.textarea-processed)'))) {
|
||||
Drupal.behaviors.textarea(teaser.parentNode);
|
||||
}
|
||||
// Set initial visibility
|
||||
if ($(teaser).is(':disabled')) {
|
||||
$(teaser).parent().hide();
|
||||
}
|
||||
|
||||
});
|
||||
};
|
35
misc/textarea.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
|
||||
Drupal.behaviors.textarea = function(context) {
|
||||
$('textarea.resizable:not(.textarea-processed)', context).each(function() {
|
||||
// Avoid non-processed teasers.
|
||||
if ($(this).is(('textarea.teaser:not(.teaser-processed)'))) {
|
||||
return false;
|
||||
}
|
||||
var textarea = $(this).addClass('textarea-processed'), staticOffset = null;
|
||||
|
||||
// When wrapping the text area, work around an IE margin bug. See:
|
||||
// http://jaspan.com/ie-inherited-margin-bug-form-elements-and-haslayout
|
||||
$(this).wrap('<div class="resizable-textarea"><span></span></div>')
|
||||
.parent().append($('<div class="grippie"></div>').mousedown(startDrag));
|
||||
|
||||
var grippie = $('div.grippie', $(this).parent())[0];
|
||||
grippie.style.marginRight = (grippie.offsetWidth - $(this)[0].offsetWidth) +'px';
|
||||
|
||||
function startDrag(e) {
|
||||
staticOffset = textarea.height() - e.pageY;
|
||||
textarea.css('opacity', 0.25);
|
||||
$(document).mousemove(performDrag).mouseup(endDrag);
|
||||
return false;
|
||||
}
|
||||
|
||||
function performDrag(e) {
|
||||
textarea.height(Math.max(32, staticOffset + e.pageY) + 'px');
|
||||
return false;
|
||||
}
|
||||
|
||||
function endDrag(e) {
|
||||
$(document).unbind("mousemove", performDrag).unbind("mouseup", endDrag);
|
||||
textarea.css('opacity', 1);
|
||||
}
|
||||
});
|
||||
};
|
BIN
misc/throbber.gif
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
misc/tree-bottom.png
Normal file
After Width: | Height: | Size: 976 B |
BIN
misc/tree.png
Normal file
After Width: | Height: | Size: 979 B |
BIN
misc/watchdog-error.png
Normal file
After Width: | Height: | Size: 799 B |
BIN
misc/watchdog-ok.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
misc/watchdog-warning.png
Normal file
After Width: | Height: | Size: 339 B |
BIN
misc/xml.png
Normal file
After Width: | Height: | Size: 396 B |