',
classes: {
// used to get elements from templates
button: 'qq-upload-button',
drop: 'qq-upload-drop-area',
dropActive: 'qq-upload-drop-area-active',
list: 'qq-upload-list',
nameInput: 'qq-upload-name-input',
overwriteInput: 'qq-overwrite-check',
uploadButton: 'qq-upload-action',
file: 'qq-upload-file',
spinner: 'qq-upload-spinner',
size: 'qq-upload-size',
cancel: 'qq-upload-cancel',
// added to list item when upload completes
// used in css to hide progress spinner
success: 'qq-upload-success',
fail: 'qq-upload-fail',
failedText: 'qq-upload-failed-text'
}
});
qq.extend(this._options, o);
this._element = this._options.element;
this._element.innerHTML = this._options.template;
this._listElement = this._options.listElement || this._find(this._element, 'list');
this._classes = this._options.classes;
this._button = this._createUploadButton(this._find(this._element, 'button'));
this._bindCancelEvent();
this._bindUploadEvent();
this._setupDragDrop();
};
qq.extend(qq.FileUploaderExtended.prototype, qq.FileUploader.prototype);
qq.extend(qq.FileUploaderExtended.prototype, {
_bindUploadEvent: function(){
var self = this,
list = this._listElement;
qq.attach(document.getElementById('mediamanager__upload_button'), 'click', function(e){
e = e || window.event;
var target = e.target || e.srcElement;
qq.preventDefault(e);
self._handler._options.onUpload();
jQuery(".qq-upload-name-input").each(function (i) {
jQuery(this).attr('disabled', 'disabled');
});
});
},
_onComplete: function(id, fileName, result){
this._filesInProgress--;
// mark completed
var item = this._getItemByFileId(id);
qq.remove(this._find(item, 'cancel'));
qq.remove(this._find(item, 'spinner'));
var nameInput = this._find(item, 'nameInput');
var fileElement = this._find(item, 'file');
qq.setText(fileElement, nameInput.value);
qq.removeClass(fileElement, 'hidden');
qq.remove(nameInput);
jQuery('.qq-upload-button, #mediamanager__upload_button').remove();
jQuery('.dw__ow').parent().hide();
jQuery('.qq-upload-drop-area').remove();
if (result.success){
qq.addClass(item, this._classes.success);
$link = '' + nameInput.value + '';
jQuery(fileElement).html($link);
} else {
qq.addClass(item, this._classes.fail);
var fail = this._find(item, 'failedText');
if (result.error) qq.setText(fail, result.error);
}
if (document.getElementById('media__content') && !document.getElementById('mediamanager__done_form')) {
var action = document.location.href;
var i = action.indexOf('?');
if (i) action = action.substr(0, i);
var button = '';
jQuery('#mediamanager__uploader').append(button);
}
}
});
qq.extend(qq.UploadHandlerForm.prototype, {
uploadAll: function(params){
this._uploadAll(params);
},
getName: function(id){
var file = this._inputs[id];
var name = document.getElementById('mediamanager__upload_item'+id);
if (name != null) {
return name.value;
} else {
if (file != null) {
// get input value and remove path to normalize
return file.value.replace(/.*(\/|\\)/, "");
} else {
return null;
}
}
},
_uploadAll: function(params){
jQuery(".qq-upload-spinner").each(function (i) {
jQuery(this).removeClass('hidden');
});
for (key in this._inputs) {
this.upload(key, params);
}
},
_upload: function(id, params){
var input = this._inputs[id];
if (!input){
throw new Error('file with passed id was not added, or already uploaded or cancelled');
}
var fileName = this.getName(id);
var iframe = this._createIframe(id);
var form = this._createForm(iframe, params);
form.appendChild(input);
var nameInput = qq.toElement('');
form.appendChild(nameInput);
var checked = jQuery('.dw__ow').is(':checked');
var owCheckbox = jQuery('.dw__ow').clone();
owCheckbox.attr('checked', checked);
jQuery(form).append(owCheckbox);
var self = this;
this._attachLoadEvent(iframe, function(){
self.log('iframe loaded');
var response = self._getIframeContentJSON(iframe);
self._options.onComplete(id, fileName, response);
self._dequeue(id);
delete self._inputs[id];
// timeout added to fix busy state in FF3.6
setTimeout(function(){
qq.remove(iframe);
}, 1);
});
form.submit();
qq.remove(form);
return id;
}
});
qq.extend(qq.UploadHandlerXhr.prototype, {
uploadAll: function(params){
this._uploadAll(params);
},
getName: function(id){
var file = this._files[id];
var name = document.getElementById('mediamanager__upload_item'+id);
if (name != null) {
return name.value;
} else {
if (file != null) {
// fix missing name in Safari 4
return file.fileName != null ? file.fileName : file.name;
} else {
return null;
}
}
},
getSize: function(id){
var file = this._files[id];
if (file == null) return null;
return file.fileSize != null ? file.fileSize : file.size;
},
_upload: function(id, params){
var file = this._files[id],
name = this.getName(id),
size = this.getSize(id);
if (name == null || size == null) return;
this._loaded[id] = 0;
var xhr = this._xhrs[id] = new XMLHttpRequest();
var self = this;
xhr.upload.onprogress = function(e){
if (e.lengthComputable){
self._loaded[id] = e.loaded;
self._options.onProgress(id, name, e.loaded, e.total);
}
};
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
self._onComplete(id, xhr);
}
};
// build query string
params = params || {};
params['qqfile'] = name;
params['ow'] = jQuery('.dw__ow').is(':checked');
var queryString = qq.obj2url(params, this._options.action);
xhr.open("POST", queryString, true);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.setRequestHeader("X-File-Name", encodeURIComponent(name));
xhr.setRequestHeader("Content-Type", "application/octet-stream");
xhr.send(file);
},
_uploadAll: function(params){
jQuery(".qq-upload-spinner").each(function (i) {
jQuery(this).removeClass('hidden');
});
for (key in this._files) {
this.upload(key, params);
}
}
});
/* XXXXXXXXXX end of lib/scripts/fileuploaderextended.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/helpers.js XXXXXXXXXX */
/**
* Various helper functions
*/
/**
* A PHP-style substr_replace
*
* Supports negative start and length and omitting length, but not
* str and replace arrays.
* See http://php.net/substr-replace for further documentation.
*/
function substr_replace(str, replace, start, length) {
var a2, b1;
a2 = (start < 0 ? str.length : 0) + start;
if (typeof length === 'undefined') {
length = str.length - a2;
} else if (length < 0 && start < 0 && length <= start) {
length = 0;
}
b1 = (length < 0 ? str.length : a2) + length;
return str.substring(0, a2) + replace + str.substring(b1);
}
/**
* Bind variables to a function call creating a closure
*
* Use this to circumvent variable scope problems when creating closures
* inside a loop
*
* @author Adrian Lang
* @link http://www.cosmocode.de/en/blog/gohr/2009-10/15-javascript-fixing-the-closure-scope-in-loops
* @param functionref fnc - the function to be called
* @param mixed - any arguments to be passed to the function
* @returns functionref
*/
function bind(fnc/*, ... */) {
var Aps = Array.prototype.slice,
// Store passed arguments in this scope.
// Since arguments is no Array nor has an own slice method,
// we have to apply the slice method from the Array.prototype
static_args = Aps.call(arguments, 1);
// Return a function evaluating the passed function with the
// given args and optional arguments passed on invocation.
return function (/* ... */) {
// Same here, but we use Array.prototype.slice solely for
// converting arguments to an Array.
return fnc.apply(this,
static_args.concat(Aps.call(arguments, 0)));
};
}
/**
* Report an error from a JS file to the console
*
* @param e The error object
* @param file The file in which the error occurred
*/
function logError(e, file) {
if (window.console && console.error) {
console.error('The error "%s: %s" occurred in file "%s". ' +
'If this is in a plugin try updating or disabling the plugin, ' +
'if this is in a template try updating the template or switching to the "dokuwiki" template.',
e.name, e.message, file);
if(e.stack) {
console.error(e.stack);
}
}
}
/* XXXXXXXXXX end of lib/scripts/helpers.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/delay.js XXXXXXXXXX */
/**
* Manage delayed and timed actions
*
* @license GPL2 (http://www.gnu.org/licenses/gpl.html)
* @author Adrian Lang
*/
/**
* Provide a global callback for window.setTimeout
*
* To get a timeout for non-global functions, just call
* delay.add(func, timeout).
*/
var timer = {
_cur_id: 0,
_handlers: {},
execDispatch: function (id) {
timer._handlers[id]();
},
add: function (func, timeout) {
var id = ++timer._cur_id;
timer._handlers[id] = func;
return window.setTimeout('timer.execDispatch(' + id + ')', timeout);
}
};
/**
* Provide a delayed start
*
* To call a function with a delay, just create a new Delay(func, timeout) and
* call that object’s method “start”.
*/
function Delay (func, timeout) {
this.func = func;
if (timeout) {
this.timeout = timeout;
}
}
Delay.prototype = {
func: null,
timeout: 500,
delTimer: function () {
if (this.timer !== null) {
window.clearTimeout(this.timer);
this.timer = null;
}
},
start: function () {
DEPRECATED('don\'t use the Delay object, use window.timeout with a callback instead');
this.delTimer();
var _this = this;
this.timer = timer.add(function () { _this.exec.call(_this); },
this.timeout);
this._data = {
_this: arguments[0],
_params: Array.prototype.slice.call(arguments, 2)
};
},
exec: function () {
this.delTimer();
this.func.call(this._data._this, this._data._params);
}
};
/* XXXXXXXXXX end of lib/scripts/delay.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/cookie.js XXXXXXXXXX */
/**
* Handles the cookie used by several JavaScript functions
*
* Only a single cookie is written and read. You may only save
* simple name-value pairs - no complex types!
*
* You should only use the getValue and setValue methods
*
* @author Andreas Gohr
* @author Michal Rezler
*/
var DokuCookie = {
data: {},
name: 'DOKU_PREFS',
/**
* Save a value to the cookie
*
* @author Andreas Gohr
*/
setValue: function(key,val){
var text = [],
_this = this;
this.init();
this.data[key] = val;
//save the whole data array
jQuery.each(_this.data, function (key, val) {
if (_this.data.hasOwnProperty(key)) {
text.push(encodeURIComponent(key)+'#'+encodeURIComponent(val));
}
});
jQuery.cookie(this.name, text.join('#'), {expires: 365, path: DOKU_COOKIE_PARAM.path, secure: DOKU_COOKIE_PARAM.secure});
},
/**
* Get a Value from the Cookie
*
* @author Andreas Gohr
*/
getValue: function(key){
this.init();
return this.data[key];
},
/**
* Loads the current set cookie
*
* @author Andreas Gohr
*/
init: function(){
var text, parts, i;
if(!jQuery.isEmptyObject(this.data)) {
return;
}
text = jQuery.cookie(this.name);
if(text){
parts = text.split('#');
for(i = 0; i < parts.length; i += 2){
this.data[decodeURIComponent(parts[i])] = decodeURIComponent(parts[i+1]);
}
}
}
};
/* XXXXXXXXXX end of lib/scripts/cookie.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/script.js XXXXXXXXXX */
// if jQuery was loaded, let's make it noConflict here.
if ('function' === typeof jQuery && 'function' === typeof jQuery.noConflict) {
jQuery.noConflict();
}
/**
* Some browser detection
*/
var clientPC = navigator.userAgent.toLowerCase(); // Get client info
var is_macos = navigator.appVersion.indexOf('Mac') != -1;
var is_gecko = ((clientPC.indexOf('gecko')!=-1) && (clientPC.indexOf('spoofer')==-1) &&
(clientPC.indexOf('khtml') == -1) && (clientPC.indexOf('netscape/7.0')==-1));
var is_safari = ((clientPC.indexOf('applewebkit')!=-1) && (clientPC.indexOf('spoofer')==-1));
var is_khtml = (navigator.vendor == 'KDE' || ( document.childNodes && !document.all && !navigator.taintEnabled ));
if (clientPC.indexOf('opera')!=-1) {
var is_opera = true;
var is_opera_preseven = (window.opera && !document.childNodes);
var is_opera_seven = (window.opera && document.childNodes);
}
/**
* Prints a animated gif to show the search is performed
*
* Because we need to modify the DOM here before the document is loaded
* and parsed completely we have to rely on document.write()
*
* @author Andreas Gohr
*/
function showLoadBar(){
document.write('');
/* this does not work reliable in IE
obj = $(id);
if(obj){
obj.innerHTML = '';
obj.style.display="block";
}
*/
}
/**
* Disables the animated gif to show the search is done
*
* @author Andreas Gohr
*/
function hideLoadBar(id){
jQuery('#' + id).hide();
}
/**
* Handler to close all open Popups
*/
function closePopups(){
jQuery('div.JSpopup').hide();
}
jQuery(function () {
jQuery(document).click(closePopups);
});
/* XXXXXXXXXX end of lib/scripts/script.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/qsearch.js XXXXXXXXXX */
/**
* AJAX functions for the pagename quicksearch
*
* @license GPL2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr
* @author Adrian Lang
* @author Michal Rezler
*/
jQuery.fn.dw_qsearch = function (overrides) {
var dw_qsearch = {
output: '#qsearch__out',
$inObj: this,
$outObj: null,
timer: null,
curRequest: null,
/**
* initialize the quick search
*
* Attaches the event handlers
*
*/
init: function () {
var do_qsearch;
dw_qsearch.$outObj = jQuery(dw_qsearch.output);
// objects found?
if (dw_qsearch.$inObj.length === 0 ||
dw_qsearch.$outObj.length === 0) {
return;
}
// attach eventhandler to search field
do_qsearch = function () {
// abort any previous request
if (dw_qsearch.curRequest != null) {
dw_qsearch.curRequest.abort();
}
var value = dw_qsearch.getSearchterm();
if (value === '') {
dw_qsearch.clear_results();
return;
}
dw_qsearch.$inObj.parents('form').addClass('searching');
dw_qsearch.curRequest = jQuery.post(
DOKU_BASE + 'lib/exe/ajax.php',
{
call: 'qsearch',
q: encodeURI(value)
},
dw_qsearch.onCompletion,
'html'
);
};
dw_qsearch.$inObj.keyup(
function () {
if (dw_qsearch.timer) {
window.clearTimeout(dw_qsearch.timer);
dw_qsearch.timer = null;
}
dw_qsearch.timer = window.setTimeout(do_qsearch, 500);
}
);
// attach eventhandler to output field
dw_qsearch.$outObj.click(dw_qsearch.clear_results);
},
/**
* Read search term from input
*/
getSearchterm: function() {
return dw_qsearch.$inObj.val();
},
/**
* Empty and hide the output div
*/
clear_results: function () {
dw_qsearch.$inObj.parents('form').removeClass('searching');
dw_qsearch.$outObj.hide();
dw_qsearch.$outObj.text('');
},
/**
* Callback. Reformat and display the results.
*
* Namespaces are shortened here to keep the results from overflowing
* or wrapping
*
* @param data The result HTML
*/
onCompletion: function (data) {
var max, $links, too_big;
dw_qsearch.$inObj.parents('form').removeClass('searching');
dw_qsearch.curRequest = null;
if (data === '') {
dw_qsearch.clear_results();
return;
}
dw_qsearch.$outObj
.html(data)
.show()
.css('white-space', 'nowrap');
// disable overflow during shortening
dw_qsearch.$outObj.find('li').css('overflow', 'visible');
$links = dw_qsearch.$outObj.find('a');
max = dw_qsearch.$outObj[0].clientWidth; // maximum width allowed (but take away paddings below)
if (document.documentElement.dir === 'rtl') {
max -= parseInt(dw_qsearch.$outObj.css('padding-left'));
too_big = function (l) {
return l.offsetLeft < 0;
};
} else {
max -= parseInt(dw_qsearch.$outObj.css('padding-right'));
too_big = function (l) {
return l.offsetWidth + l.offsetLeft > max;
};
}
$links.each(function () {
var start, length, replace, nsL, nsR, eli, runaway;
if (!too_big(this)) {
return;
}
nsL = this.textContent.indexOf('(');
nsR = this.textContent.indexOf(')');
eli = 0;
runaway = 0;
while ((nsR - nsL > 3) && too_big(this) && runaway++ < 500) {
if (eli !== 0) {
// elipsis already inserted
if ((eli - nsL) > (nsR - eli)) {
// cut left
start = eli - 2;
length = 2;
} else {
// cut right
start = eli + 1;
length = 1;
}
replace = '';
} else {
// replace middle with ellipsis
start = Math.floor(nsL + ((nsR - nsL) / 2));
length = 1;
replace = '…';
}
this.textContent = substr_replace(this.textContent,
replace, start, length);
eli = this.textContent.indexOf('…');
nsL = this.textContent.indexOf('(');
nsR = this.textContent.indexOf(')');
}
});
// reenable overflow
dw_qsearch.$outObj.find('li').css('overflow', 'hidden').css('text-overflow', 'ellipsis');
}
};
jQuery.extend(dw_qsearch, overrides);
if (!overrides.deferInit) {
dw_qsearch.init();
}
return dw_qsearch;
};
jQuery(function () {
jQuery('#qsearch__in').dw_qsearch({
output: '#qsearch__out'
});
});
/* XXXXXXXXXX end of lib/scripts/qsearch.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/tree.js XXXXXXXXXX */
jQuery.fn.dw_tree = function(overrides) {
var dw_tree = {
/**
* Delay in ms before showing the throbber.
* Used to skip the throbber for fast AJAX calls.
*/
throbber_delay: 500,
$obj: this,
toggle_selector: 'a.idx_dir',
init: function () {
this.$obj.on('click', this.toggle_selector, this,
this.toggle);
jQuery('ul:first', this.$obj).attr('role', 'tree');
jQuery('ul', this.$obj).not(':first').attr('role', 'group');
jQuery('li', this.$obj).attr('role', 'treeitem');
jQuery('li.open > ul', this.$obj).attr('aria-expanded', 'true');
jQuery('li.closed > ul', this.$obj).attr('aria-expanded', 'false');
jQuery('li.closed', this.$obj).attr('aria-live', 'assertive');
},
/**
* Open or close a subtree using AJAX
* The contents of subtrees are "cached" until the page is reloaded.
* A "loading" indicator is shown only when the AJAX call is slow.
*
* @author Andreas Gohr
* @author Ben Coburn
* @author Pierre Spring
*/
toggle: function (e) {
var $listitem, $sublist, timeout, $clicky, show_sublist, dw_tree, opening;
e.preventDefault();
dw_tree = e.data;
$clicky = jQuery(this);
$listitem = $clicky.closest('li');
$sublist = $listitem.find('ul').first();
opening = $listitem.hasClass('closed');
dw_tree.toggle_display($clicky, opening);
if ($sublist.is(':visible')) {
$listitem.removeClass('open').addClass('closed');
$sublist.attr('aria-expanded', 'false');
} else {
$listitem.removeClass('closed').addClass('open');
$sublist.attr('aria-expanded', 'true');
}
// if already open, close by hiding the sublist
if (!opening) {
$sublist.dw_hide();
return;
}
show_sublist = function (data) {
$sublist.hide();
if (typeof data !== 'undefined') {
$sublist.html(data);
$sublist.parent().attr('aria-busy', 'false').removeAttr('aria-live');
jQuery('li.closed', $sublist).attr('aria-live', 'assertive');
}
if ($listitem.hasClass('open')) {
// Only show if user didn’t close the list since starting
// to load the content
$sublist.dw_show();
}
};
// just show if already loaded
if ($sublist.length > 0) {
show_sublist();
return;
}
//prepare the new ul
$sublist = jQuery('
');
$listitem.append($sublist);
timeout = window.setTimeout(
bind(show_sublist, ''), dw_tree.throbber_delay);
dw_tree.load_data(function (data) {
window.clearTimeout(timeout);
show_sublist(data);
}, $clicky);
},
toggle_display: function ($clicky, opening) {
},
load_data: function (show_data, $clicky) {
show_data();
}
};
jQuery.extend(dw_tree, overrides);
if (!overrides.deferInit) {
dw_tree.init();
}
return dw_tree;
};
/* XXXXXXXXXX end of lib/scripts/tree.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/index.js XXXXXXXXXX */
var dw_index = jQuery('#index__tree').dw_tree({deferInit: true,
load_data: function (show_sublist, $clicky) {
jQuery.post(
DOKU_BASE + 'lib/exe/ajax.php',
$clicky[0].search.substr(1) + '&call=index',
show_sublist, 'html'
);
}
});
jQuery(function () {
var $tree = jQuery('#index__tree');
dw_index.$obj = $tree;
dw_index.init();
});
/* XXXXXXXXXX end of lib/scripts/index.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/textselection.js XXXXXXXXXX */
/**
* Text selection related functions.
*/
/**
* selection prototype
*
* Object that capsulates the selection in a textarea. Returned by DWgetSelection.
*
* @author Andreas Gohr
*/
function selection_class(){
this.start = 0;
this.end = 0;
this.obj = null;
this.scroll = 0;
this.fix = 0;
this.getLength = function(){
return this.end - this.start;
};
this.getText = function(){
return (!this.obj) ? '' : this.obj.value.substring(this.start,this.end);
};
}
/**
* Get current selection/cursor position in a given textArea
*
* @link http://groups.drupal.org/node/1210
* @author Andreas Gohr
* @link http://linebyline.blogspot.com/2006/11/textarea-cursor-position-in-internet.html
* @returns object - a selection object
*/
function DWgetSelection(textArea) {
var sel = new selection_class();
textArea.focus();
sel.obj = textArea;
sel.start = textArea.selectionStart;
sel.end = textArea.selectionEnd;
sel.scroll = textArea.scrollTop;
return sel;
}
/**
* Set the selection
*
* You need to get a selection object via DWgetSelection() first, then modify the
* start and end properties and pass it back to this function.
*
* @link http://groups.drupal.org/node/1210
* @author Andreas Gohr
* @param {selection_class} selection a selection object as returned by DWgetSelection()
*/
function DWsetSelection(selection){
selection.obj.setSelectionRange(selection.start, selection.end);
if(selection.scroll) selection.obj.scrollTop = selection.scroll;
}
/**
* Inserts the given text at the current cursor position or replaces the current
* selection
*
* @author Andreas Gohr
* @param {string} text the new text to be pasted
* @param {selection_class} selection selection object returned by DWgetSelection
* @param {int} opts.startofs number of charcters at the start to skip from new selection
* @param {int} opts.endofs number of characters at the end to skip from new selection
* @param {boolean} opts.nosel set true if new text should not be selected
*/
function pasteText(selection,text,opts){
if(!opts) opts = {};
// replace the content
selection.obj.value =
selection.obj.value.substring(0, selection.start) + text +
selection.obj.value.substring(selection.end, selection.obj.value.length);
// set new selection
if (is_opera) {
// Opera replaces \n by \r\n when inserting text.
selection.end = selection.start + text.replace(/\r?\n/g, '\r\n').length;
} else {
selection.end = selection.start + text.length;
}
// modify the new selection if wanted
if(opts.startofs) selection.start += opts.startofs;
if(opts.endofs) selection.end -= opts.endofs;
// no selection wanted? set cursor to end position
if(opts.nosel) selection.start = selection.end;
DWsetSelection(selection);
}
/**
* Format selection
*
* Apply tagOpen/tagClose to selection in textarea, use sampleText instead
* of selection if there is none.
*
* @author Andreas Gohr
*/
function insertTags(textAreaID, tagOpen, tagClose, sampleText){
var txtarea = jQuery('#' + textAreaID)[0];
var selection = DWgetSelection(txtarea);
var text = selection.getText();
var opts;
// don't include trailing space in selection
if(text.charAt(text.length - 1) == ' '){
selection.end--;
text = selection.getText();
}
if(!text){
// nothing selected, use the sample text and select it
text = sampleText;
opts = {
startofs: tagOpen.length,
endofs: tagClose.length
};
}else{
// place cursor at the end
opts = {
nosel: true
};
}
// surround with tags
text = tagOpen + text + tagClose;
// do it
pasteText(selection,text,opts);
}
/**
* Wraps around pasteText() for backward compatibility
*
* @author Andreas Gohr
*/
function insertAtCarret(textAreaID, text){
var txtarea = jQuery('#' + textAreaID)[0];
var selection = DWgetSelection(txtarea);
pasteText(selection,text,{nosel: true});
}
/* XXXXXXXXXX end of lib/scripts/textselection.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/toolbar.js XXXXXXXXXX */
// used to identify pickers
var pickercounter=0;
/**
* Create a toolbar
*
* @param string tbid ID of the element where to insert the toolbar
* @param string edid ID of the editor textarea
* @param array tb Associative array defining the buttons
* @param bool allowblock Allow buttons creating multiline content
* @author Andreas Gohr
*/
function initToolbar(tbid,edid,tb, allowblock){
var $toolbar, $edit;
if (typeof tbid == 'string') {
$toolbar = jQuery('#' + tbid);
} else {
$toolbar = jQuery(tbid);
}
$edit = jQuery('#' + edid);
if ($toolbar.length == 0 || $edit.length == 0 || $edit.attr('readOnly')) {
return;
}
if (typeof allowblock === 'undefined') {
allowblock = true;
}
//empty the toolbar area:
$toolbar.html('');
jQuery.each(tb, function (k, val) {
if (!tb.hasOwnProperty(k) || (!allowblock && val.block === true)) {
return;
}
var actionFunc, $btn;
// create new button (jQuery object)
$btn = jQuery(createToolButton(val.icon, val.title, val.key, val.id,
val['class']));
// type is a tb function -> assign it as onclick
actionFunc = 'tb_'+val.type;
if( jQuery.isFunction(window[actionFunc]) ){
$btn.on('click', bind(window[actionFunc],$btn,val,edid) );
$toolbar.append($btn);
return;
}
// type is a init function -> execute it
actionFunc = 'addBtnAction'+val.type.charAt(0).toUpperCase()+val.type.substring(1);
if( jQuery.isFunction(window[actionFunc]) ){
var pickerid = window[actionFunc]($btn, val, edid);
if(pickerid !== ''){
$toolbar.append($btn);
$btn.attr('aria-controls', pickerid);
if (actionFunc === 'addBtnActionPicker') {
$btn.attr('aria-haspopup', 'true');
}
}
return;
}
alert('unknown toolbar type: '+val.type+' '+actionFunc);
});
}
/**
* Button action for format buttons
*
* @param DOMElement btn Button element to add the action to
* @param array props Associative array of button properties
* @param string edid ID of the editor textarea
* @author Gabriel Birke
* @author Andreas Gohr
*/
function tb_format(btn, props, edid) {
var sample = props.sample || props.title;
insertTags(edid,
fixtxt(props.open),
fixtxt(props.close),
fixtxt(sample));
pickerClose();
return false;
}
/**
* Button action for format buttons
*
* This works exactly as tb_format() except that, if multiple lines
* are selected, each line will be formatted seperately
*
* @param DOMElement btn Button element to add the action to
* @param array props Associative array of button properties
* @param string edid ID of the editor textarea
* @author Gabriel Birke
* @author Andreas Gohr
*/
function tb_formatln(btn, props, edid) {
var sample = props.sample || props.title,
opts,
selection = DWgetSelection(jQuery('#'+edid)[0]);
sample = fixtxt(sample);
props.open = fixtxt(props.open);
props.close = fixtxt(props.close);
// is something selected?
if(selection.getLength()){
sample = selection.getText();
opts = {nosel: true};
}else{
opts = {
startofs: props.open.length,
endofs: props.close.length
};
}
sample = sample.split("\n").join(props.close+"\n"+props.open);
sample = props.open+sample+props.close;
pasteText(selection,sample,opts);
pickerClose();
return false;
}
/**
* Button action for insert buttons
*
* @param DOMElement btn Button element to add the action to
* @param array props Associative array of button properties
* @param string edid ID of the editor textarea
* @author Gabriel Birke
* @author Andreas Gohr
*/
function tb_insert(btn, props, edid) {
insertAtCarret(edid,fixtxt(props.insert));
pickerClose();
return false;
}
/**
* Button action for the media popup
*
* @param DOMElement btn Button element to add the action to
* @param array props Associative array of button properties
* @param string edid ID of the editor textarea
* @author Andreas Gohr
*/
function tb_mediapopup(btn, props, edid) {
window.open(
DOKU_BASE+props.url+encodeURIComponent(NS)+'&edid='+encodeURIComponent(edid),
props.name,
props.options);
return false;
}
/**
* Button action for automatic headlines
*
* Insert a new headline based on the current section level
*
* @param DOMElement btn Button element to add the action to
* @param array props Associative array of button properties
* @param string edid ID of the editor textarea
* @author Andreas Gohr
*/
function tb_autohead(btn, props, edid){
var lvl = currentHeadlineLevel(edid),
tags;
// determine new level
lvl += props.mod;
if(lvl < 1) lvl = 1;
if(lvl > 5) lvl = 5;
tags = (new Array(8 - lvl)).join('=');
insertTags(edid, tags+' ', ' '+tags+"\n", props.text);
pickerClose();
return false;
}
/**
* Add button action for picker buttons and create picker element
*
* @param jQuery btn Button element to add the action to
* @param array props Associative array of button properties
* @param string edid ID of the editor textarea
* @return boolean If button should be appended
* @author Gabriel Birke
*/
function addBtnActionPicker($btn, props, edid) {
var pickerid = 'picker'+(pickercounter++);
var picker = createPicker(pickerid, props, edid);
jQuery(picker).attr('aria-hidden', 'true');
$btn.click(
function(e) {
pickerToggle(pickerid,$btn);
e.preventDefault();
return '';
}
);
return pickerid;
}
/**
* Add button action for the link wizard button
*
* @param DOMElement btn Button element to add the action to
* @param array props Associative array of button properties
* @param string edid ID of the editor textarea
* @return boolean If button should be appended
* @author Andreas Gohr
*/
function addBtnActionLinkwiz($btn, props, edid) {
dw_linkwiz.init(jQuery('#'+edid));
jQuery($btn).click(function(e){
dw_linkwiz.val = props;
dw_linkwiz.toggle();
e.preventDefault();
return '';
});
return 'link__wiz';
}
/**
* Show/Hide a previously created picker window
*
* @author Andreas Gohr
*/
function pickerToggle(pickerid,$btn){
var $picker = jQuery('#' + pickerid),
pos = $btn.offset();
if ($picker.hasClass('a11y')) {
$picker.removeClass('a11y').attr('aria-hidden', 'false');
} else {
$picker.addClass('a11y').attr('aria-hidden', 'true');
}
var picker_left = pos.left + 3,
picker_width = $picker.width(),
window_width = jQuery(window).width();
if (picker_width > 300) {
$picker.css("max-width", "300");
picker_width = 300;
}
if ((picker_left + picker_width + 40) > window_width) {
picker_left = window_width - picker_width - 40;
}
if (picker_left < 0) {
picker_left = 0;
}
$picker.offset({left: picker_left, top: pos.top+$btn[0].offsetHeight+3});
}
/**
* Close all open pickers
*
* @author Andreas Gohr
*/
function pickerClose(){
jQuery('.picker').addClass('a11y');
}
/**
* Replaces \n with linebreaks
*/
function fixtxt(str){
return str.replace(/\\n/g,"\n");
}
jQuery(function () {
initToolbar('tool__bar','wiki__text',toolbar);
jQuery('#tool__bar').attr('role', 'toolbar');
});
/* XXXXXXXXXX end of lib/scripts/toolbar.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/edit.js XXXXXXXXXX */
/**
* Functions for text editing (toolbar stuff)
*
* @todo most of the stuff in here should be revamped and then moved to toolbar.js
* @author Andreas Gohr
*/
/**
* Creates a toolbar button through the DOM
* Called for each entry of toolbar definition array (built by inc/toolbar.php and extended via js)
*
* Style the buttons through the toolbutton class
*
* @param {string} icon image filename, relative to folder lib/images/toolbar/
* @param {string} label title of button, show on mouseover
* @param {string} key hint in title of button for access key
* @param {string} id id of button, and '_ico' of icon
* @param {string} classname for styling buttons
*
* @author Andreas Gohr
* @author Michal Rezler
*/
function createToolButton(icon,label,key,id,classname){
var $btn = jQuery(document.createElement('button')),
$ico = jQuery(document.createElement('img'));
// prepare the basic button stuff
$btn.addClass('toolbutton');
if(classname){
$btn.addClass(classname);
}
$btn.attr('title', label).attr('aria-controls', 'wiki__text');
if(key){
$btn.attr('title', label + ' ['+key.toUpperCase()+']')
.attr('accessKey', key);
}
// set IDs if given
if(id){
$btn.attr('id', id);
$ico.attr('id', id+'_ico');
}
// create the icon and add it to the button
if(icon.substr(0,1) !== '/'){
icon = DOKU_BASE + 'lib/images/toolbar/' + icon;
}
$ico.attr('src', icon);
$ico.attr('alt', '');
$ico.attr('width', 16);
$ico.attr('height', 16);
$btn.append($ico);
// we have to return a DOM object (for compatibility reasons)
return $btn[0];
}
/**
* Creates a picker window for inserting text
*
* The given list can be an associative array with text,icon pairs
* or a simple list of text. Style the picker window through the picker
* class or the picker buttons with the pickerbutton class. Picker
* windows are appended to the body and created invisible.
*
* @param {string} id the ID to assign to the picker
* @param {Array} props the properties for the picker
* @param {string} edid the ID of the textarea
* @return DOMobject the created picker
* @author Andreas Gohr
*/
function createPicker(id,props,edid){
// create the wrapping div
var $picker = jQuery(document.createElement('div'));
$picker.addClass('picker a11y');
if(props['class']){
$picker.addClass(props['class']);
}
$picker.attr('id', id).css('position', 'absolute');
function $makebutton(title) {
var $btn = jQuery(document.createElement('button'))
.addClass('pickerbutton').attr('title', title)
.attr('aria-controls', edid)
.on('click', bind(pickerInsert, title, edid))
.appendTo($picker);
return $btn;
}
jQuery.each(props.list, function (key, item) {
if (!props.list.hasOwnProperty(key)) {
return;
}
if(isNaN(key)){
// associative array -> treat as text => image pairs
if (item.substr(0,1) !== '/') {
item = DOKU_BASE+'lib/images/'+props.icobase+'/'+item;
}
jQuery(document.createElement('img'))
.attr('src', item)
.attr('alt', '')
.appendTo($makebutton(key));
}else if (typeof item == 'string'){
// a list of text -> treat as text picker
$makebutton(item).text(item);
}else{
// a list of lists -> treat it as subtoolbar
initToolbar($picker,edid,props.list);
return false; // all buttons handled already
}
});
jQuery('body').append($picker);
// we have to return a DOM object (for compatibility reasons)
return $picker[0];
}
/**
* Called by picker buttons to insert Text and close the picker again
*
* @author Andreas Gohr
*/
function pickerInsert(text,edid){
insertAtCarret(edid,text);
pickerClose();
}
/**
* Add button action for signature button
*
* @param {jQuery} $btn Button element to add the action to
* @param {Array} props Associative array of button properties
* @param {string} edid ID of the editor textarea
* @return {string} picker id for aria-controls attribute
* @author Gabriel Birke
*/
function addBtnActionSignature($btn, props, edid) {
if(typeof SIG != 'undefined' && SIG != ''){
$btn.on('click', function (e) {
insertAtCarret(edid,SIG);
e.preventDefault();
});
return edid;
}
return '';
}
/**
* Determine the current section level while editing
*
* @param {string} textboxId ID of the text field
*
* @author Andreas Gohr
*/
function currentHeadlineLevel(textboxId){
var field = jQuery('#' + textboxId)[0],
s = false,
opts = [field.value.substr(0,DWgetSelection(field).start)];
if (field.form.prefix) {
// we need to look in prefix context
opts.push(field.form.prefix.value);
}
jQuery.each(opts, function (_, opt) {
// Check whether there is a headline in the given string
var str = "\n" + opt,
lasthl = str.lastIndexOf("\n==");
if (lasthl !== -1) {
s = str.substr(lasthl+1,6);
return false;
}
});
if (s === false) {
return 0;
}
return 7 - s.match(/^={2,6}/)[0].length;
}
/**
* global var used for not saved yet warning
*/
window.textChanged = false;
/**
* global var which stores original editor content
*/
window.doku_edit_text_content = '';
/**
* Delete the draft before leaving the page
*/
function deleteDraft() {
if (is_opera || window.keepDraft) {
return;
}
var $dwform = jQuery('#dw__editform');
if($dwform.length === 0) {
return;
}
// remove a possibly saved draft using ajax
jQuery.post(DOKU_BASE + 'lib/exe/ajax.php',
{
call: 'draftdel',
id: $dwform.find('input[name=id]').val()
}
);
}
/**
* Activate "not saved" dialog, add draft deletion to page unload,
* add handlers to monitor changes
* Note: textChanged could be set by e.g. html_edit() as well
*
* Sets focus to the editbox as well
*/
jQuery(function () {
var $editform = jQuery('#dw__editform');
if ($editform.length == 0) {
return;
}
var $edit_text = jQuery('#wiki__text');
if ($edit_text.length > 0) {
if($edit_text.attr('readOnly')) {
return;
}
// set focus and place cursor at the start
var sel = DWgetSelection($edit_text[0]);
sel.start = 0;
sel.end = 0;
DWsetSelection(sel);
$edit_text.focus();
doku_edit_text_content = $edit_text.val();
}
var changeHandler = function() {
doku_hasTextBeenModified();
doku_summaryCheck();
};
$editform.change(changeHandler);
$editform.keydown(changeHandler);
window.onbeforeunload = function(){
if(window.textChanged) {
return LANG.notsavedyet;
}
};
window.onunload = deleteDraft;
// reset change memory var on submit
jQuery('#edbtn__save').click(
function() {
window.onbeforeunload = '';
textChanged = false;
}
);
jQuery('#edbtn__preview').click(
function() {
window.onbeforeunload = '';
textChanged = false;
window.keepDraft = true; // needed to keep draft on page unload
}
);
var $summary = jQuery('#edit__summary');
$summary.change(doku_summaryCheck);
$summary.keyup(doku_summaryCheck);
if (textChanged) doku_summaryCheck();
});
/**
* Updates textChanged variable if content of the editor has been modified
*/
function doku_hasTextBeenModified() {
if (!textChanged) {
var $edit_text = jQuery('#wiki__text');
if ($edit_text.length > 0) {
textChanged = doku_edit_text_content != $edit_text.val();
} else {
textChanged = true;
}
}
}
/**
* Checks if a summary was entered - if not the style is changed
*
* @author Andreas Gohr
*/
function doku_summaryCheck(){
var $sum = jQuery('#edit__summary'),
missing = $sum.val() === '';
$sum.toggleClass('missing', missing).toggleClass('edit', !missing);
}
/* XXXXXXXXXX end of lib/scripts/edit.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/editor.js XXXXXXXXXX */
/**
* The DokuWiki editor features
*
* These are the advanced features of the editor. It does NOT contain any
* code for the toolbar buttons and it functions. See toolbar.js for that.
*/
var dw_editor = {
/**
* initialize the default editor functionality
*
* All other functions can also be called separately for non-default
* textareas
*/
init: function(){
var $editor = jQuery('#wiki__text');
if($editor.length === 0) {
return;
}
dw_editor.initSizeCtl('#size__ctl',$editor);
if($editor.attr('readOnly')) {
return;
}
$editor.keydown(dw_editor.keyHandler);
},
/**
* Add the edit window size and wrap controls
*
* Initial values are read from cookie if it exists
*
* @param selector ctlarea the div to place the controls
* @param selector editor the textarea to control
*/
initSizeCtl: function(ctlarea,editor){
var $ctl = jQuery(ctlarea),
$textarea = jQuery(editor);
if($ctl.length === 0 || $textarea.length === 0) {
return;
}
$textarea.css('height', DokuCookie.getValue('sizeCtl') || '300px');
var wrp = DokuCookie.getValue('wrapCtl');
if(wrp){
dw_editor.setWrap($textarea[0], wrp);
} // else use default value
jQuery.each([
['larger', function(){dw_editor.sizeCtl(editor,100);}],
['smaller', function(){dw_editor.sizeCtl(editor,-100);}],
['wrap', function(){dw_editor.toggleWrap(editor);}]
], function (_, img) {
jQuery(document.createElement('img'))
.attr('src', DOKU_BASE+'lib/images/' + img[0] + '.gif')
.attr('alt', '')
.click(img[1])
.appendTo($ctl);
});
},
/**
* This sets the vertical size of the editbox and adjusts the cookie
*
* @param selector editor the textarea to control
* @param int val the relative value to resize in pixel
*/
sizeCtl: function(editor,val){
var $textarea = jQuery(editor),
height = parseInt($textarea.css('height')) + val;
$textarea.css('height', height+'px');
DokuCookie.setValue('sizeCtl',$textarea.css('height'));
},
/**
* Toggle the wrapping mode of the editor textarea and adjusts the
* cookie
*
* @param selector editor the textarea to control
*/
toggleWrap: function(editor){
var $textarea = jQuery(editor),
wrap = $textarea.attr('wrap');
dw_editor.setWrap($textarea[0],
(wrap && wrap.toLowerCase() == 'off') ? 'soft' : 'off');
DokuCookie.setValue('wrapCtl',$textarea.attr('wrap'));
},
/**
* Set the wrapping mode of a textarea
*
* @author Fluffy Convict
* @author
* @link http://news.hping.org/comp.lang.javascript.archive/12265.html
* @link https://bugzilla.mozilla.org/show_bug.cgi?id=41464
* @param DomObject textarea
* @param string wrapAttrValue
*/
setWrap: function(textarea, wrapAttrValue){
textarea.setAttribute('wrap', wrapAttrValue);
// Fix display for mozilla
var parNod = textarea.parentNode;
var nxtSib = textarea.nextSibling;
parNod.removeChild(textarea);
parNod.insertBefore(textarea, nxtSib);
},
/**
* Make intended formattings easier to handle
*
* Listens to all key inputs and handle indentions
* of lists and code blocks
*
* Currently handles space, backspace, enter and
* ctrl-enter presses
*
* @author Andreas Gohr
* @fixme handle tabs
* @param event e - the key press event object
*/
keyHandler: function(e){
if(jQuery.inArray(e.keyCode,[8, 10, 13, 32]) === -1) {
return;
}
var selection = DWgetSelection(this);
if(selection.getLength() > 0) {
return; //there was text selected, keep standard behavior
}
var search = "\n"+this.value.substr(0,selection.start);
var linestart = Math.max(search.lastIndexOf("\n"),
search.lastIndexOf("\r")); //IE workaround
search = search.substr(linestart);
if((e.keyCode == 13 || e.keyCode == 10) && e.ctrlKey) { // Ctrl-Enter (With Chrome workaround)
// Submit current edit
jQuery('#edbtn__save').click();
e.preventDefault(); // prevent enter key
return false;
}else if(e.keyCode == 13){ // Enter
// keep current indention for lists and code
var match = search.match(/(\n +([\*-] ?)?)/);
if(match){
var scroll = this.scrollHeight;
var match2 = search.match(/^\n +[\*-]\s*$/);
// Cancel list if the last item is empty (i. e. two times enter)
if (match2 && this.value.substr(selection.start).match(/^($|\r?\n)/)) {
this.value = this.value.substr(0, linestart) + "\n" +
this.value.substr(selection.start);
selection.start = linestart + 1;
selection.end = linestart + 1;
DWsetSelection(selection);
} else {
insertAtCarret(this.id,match[1]);
}
this.scrollTop += (this.scrollHeight - scroll);
e.preventDefault(); // prevent enter key
return false;
}
}else if(e.keyCode == 8){ // Backspace
// unindent lists
var match = search.match(/(\n +)([*-] ?)$/);
if(match){
var spaces = match[1].length-1;
if(spaces > 3){ // unindent one level
this.value = this.value.substr(0,linestart)+
this.value.substr(linestart+2);
selection.start = selection.start - 2;
selection.end = selection.start;
}else{ // delete list point
this.value = this.value.substr(0,linestart)+
this.value.substr(selection.start);
selection.start = linestart;
selection.end = linestart;
}
DWsetSelection(selection);
e.preventDefault(); // prevent backspace
return false;
}
}else if(e.keyCode == 32){ // Space
// intend list item
var match = search.match(/(\n +)([*-] )$/);
if(match){
this.value = this.value.substr(0,linestart)+' '+
this.value.substr(linestart);
selection.start = selection.start + 2;
selection.end = selection.start;
DWsetSelection(selection);
e.preventDefault(); // prevent space
return false;
}
}
}
};
jQuery(dw_editor.init);
/* XXXXXXXXXX end of lib/scripts/editor.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/locktimer.js XXXXXXXXXX */
/**
* Class managing the timer to display a warning on a expiring lock
*/
var dw_locktimer = {
timeout: 0,
draft: false,
timerID: null,
lasttime: null,
msg: LANG.willexpire,
pageid: '',
/**
* Initialize the lock timer
*
* @param {int} timeout Length of timeout in seconds
* @param {bool} draft Whether to save drafts
* @param {string} edid Optional; ID of an edit object which has to be present
*/
init: function(timeout,draft,edid){
var $edit;
edid = edid || 'wiki__text';
$edit = jQuery('#' + edid);
if($edit.length === 0 || $edit.attr('readonly')) {
return;
}
// init values
dw_locktimer.timeout = timeout*1000;
dw_locktimer.draft = draft;
dw_locktimer.lasttime = new Date();
dw_locktimer.pageid = jQuery('#dw__editform').find('input[name=id]').val();
if(!dw_locktimer.pageid) {
return;
}
// register refresh event
$edit.keypress(dw_locktimer.refresh);
// start timer
dw_locktimer.reset();
},
/**
* (Re)start the warning timer
*/
reset: function(){
dw_locktimer.clear();
dw_locktimer.timerID = window.setTimeout(dw_locktimer.warning, dw_locktimer.timeout);
},
/**
* Display the warning about the expiring lock
*/
warning: function(){
dw_locktimer.clear();
alert(fixtxt(dw_locktimer.msg));
},
/**
* Remove the current warning timer
*/
clear: function(){
if(dw_locktimer.timerID !== null){
window.clearTimeout(dw_locktimer.timerID);
dw_locktimer.timerID = null;
}
},
/**
* Refresh the lock via AJAX
*
* Called on keypresses in the edit area
*/
refresh: function(){
var now = new Date(),
params = 'call=lock&id=' + dw_locktimer.pageid + '&';
// refresh every minute only
if(now.getTime() - dw_locktimer.lasttime.getTime() <= 30*1000) {
return;
}
// POST everything necessary for draft saving
if(dw_locktimer.draft && jQuery('#dw__editform').find('textarea[name=wikitext]').length > 0){
params += jQuery('#dw__editform').find('input[name=prefix], ' +
'textarea[name=wikitext], ' +
'input[name=suffix], ' +
'input[name=date]').serialize();
}
jQuery.post(
DOKU_BASE + 'lib/exe/ajax.php',
params,
dw_locktimer.refreshed,
'html'
);
dw_locktimer.lasttime = now;
},
/**
* Callback. Resets the warning timer
*/
refreshed: function(data){
var error = data.charAt(0);
data = data.substring(1);
jQuery('#draft__status').html(data);
if(error != '1') {
return; // locking failed
}
dw_locktimer.reset();
}
};
/* XXXXXXXXXX end of lib/scripts/locktimer.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/linkwiz.js XXXXXXXXXX */
/**
* The Link Wizard
*
* @author Andreas Gohr
* @author Pierre Spring
*/
var dw_linkwiz = {
$wiz: null,
$entry: null,
result: null,
timer: null,
textArea: null,
selected: null,
selection: null,
/**
* Initialize the dw_linkwizard by creating the needed HTML
* and attaching the eventhandlers
*/
init: function($editor){
// position relative to the text area
var pos = $editor.position();
// create HTML Structure
if(dw_linkwiz.$wiz)
return;
dw_linkwiz.$wiz = jQuery(document.createElement('div'))
.dialog({
autoOpen: false,
draggable: true,
title: LANG.linkwiz,
resizable: false
})
.html(
'
'+LANG.linkto+'
'+
''
)
.parent()
.attr('id','link__wiz')
.css({
'position': 'absolute',
'top': (pos.top+20)+'px',
'left': (pos.left+80)+'px'
})
.hide()
.appendTo('.dokuwiki:first');
dw_linkwiz.textArea = $editor[0];
dw_linkwiz.result = jQuery('#link__wiz_result')[0];
// scrollview correction on arrow up/down gets easier
jQuery(dw_linkwiz.result).css('position', 'relative');
dw_linkwiz.$entry = jQuery('#link__wiz_entry');
if(JSINFO.namespace){
dw_linkwiz.$entry.val(JSINFO.namespace+':');
}
// attach event handlers
jQuery('#link__wiz .ui-dialog-titlebar-close').click(dw_linkwiz.hide);
dw_linkwiz.$entry.keyup(dw_linkwiz.onEntry);
jQuery(dw_linkwiz.result).on('click', 'a', dw_linkwiz.onResultClick);
},
/**
* handle all keyup events in the entry field
*/
onEntry: function(e){
if(e.keyCode == 37 || e.keyCode == 39){ //left/right
return true; //ignore
}
if(e.keyCode == 27){ //Escape
dw_linkwiz.hide();
e.preventDefault();
e.stopPropagation();
return false;
}
if(e.keyCode == 38){ //Up
dw_linkwiz.select(dw_linkwiz.selected -1);
e.preventDefault();
e.stopPropagation();
return false;
}
if(e.keyCode == 40){ //Down
dw_linkwiz.select(dw_linkwiz.selected +1);
e.preventDefault();
e.stopPropagation();
return false;
}
if(e.keyCode == 13){ //Enter
if(dw_linkwiz.selected > -1){
var $obj = dw_linkwiz.$getResult(dw_linkwiz.selected);
if($obj.length > 0){
dw_linkwiz.resultClick($obj.find('a')[0]);
}
}else if(dw_linkwiz.$entry.val()){
dw_linkwiz.insertLink(dw_linkwiz.$entry.val());
}
e.preventDefault();
e.stopPropagation();
return false;
}
dw_linkwiz.autocomplete();
},
/**
* Get one of the results by index
*
* @param num int result div to return
* @returns DOMObject or null
*/
getResult: function(num){
DEPRECATED('use dw_linkwiz.$getResult()[0] instead');
return dw_linkwiz.$getResult()[0] || null;
},
/**
* Get one of the results by index
*
* @param num int result div to return
* @returns jQuery object
*/
$getResult: function(num) {
return jQuery(dw_linkwiz.result).find('div').eq(num);
},
/**
* Select the given result
*/
select: function(num){
if(num < 0){
dw_linkwiz.deselect();
return;
}
var $obj = dw_linkwiz.$getResult(num);
if ($obj.length === 0) {
return;
}
dw_linkwiz.deselect();
$obj.addClass('selected');
// make sure the item is viewable in the scroll view
//getting child position within the parent
var childPos = $obj.position().top;
//getting difference between the childs top and parents viewable area
var yDiff = childPos + $obj.outerHeight() - jQuery(dw_linkwiz.result).innerHeight();
if (childPos < 0) {
//if childPos is above viewable area (that's why it goes negative)
jQuery(dw_linkwiz.result)[0].scrollTop += childPos;
} else if(yDiff > 0) {
// if difference between childs top and parents viewable area is
// greater than the height of a childDiv
jQuery(dw_linkwiz.result)[0].scrollTop += yDiff;
}
dw_linkwiz.selected = num;
},
/**
* deselect a result if any is selected
*/
deselect: function(){
if(dw_linkwiz.selected > -1){
dw_linkwiz.$getResult(dw_linkwiz.selected).removeClass('selected');
}
dw_linkwiz.selected = -1;
},
/**
* Handle clicks in the result set an dispatch them to
* resultClick()
*/
onResultClick: function(e){
if(!jQuery(this).is('a')) {
return;
}
e.stopPropagation();
e.preventDefault();
dw_linkwiz.resultClick(this);
return false;
},
/**
* Handles the "click" on a given result anchor
*/
resultClick: function(a){
dw_linkwiz.$entry.val(a.title);
if(a.title == '' || a.title.substr(a.title.length-1) == ':'){
dw_linkwiz.autocomplete_exec();
}else{
if (jQuery(a.nextSibling).is('span')) {
dw_linkwiz.insertLink(a.nextSibling.innerHTML);
}else{
dw_linkwiz.insertLink('');
}
}
},
/**
* Insert the id currently in the entry box to the textarea,
* replacing the current selection or at the cursor position.
* When no selection is available the given title will be used
* as link title instead
*/
insertLink: function(title){
var link = dw_linkwiz.$entry.val(),
sel, stxt;
if(!link) {
return;
}
sel = DWgetSelection(dw_linkwiz.textArea);
if(sel.start == 0 && sel.end == 0) {
sel = dw_linkwiz.selection;
}
stxt = sel.getText();
// don't include trailing space in selection
if(stxt.charAt(stxt.length - 1) == ' '){
sel.end--;
stxt = sel.getText();
}
if(!stxt && !DOKU_UHC) {
stxt=title;
}
// prepend colon inside namespaces for non namespace pages
if(dw_linkwiz.textArea.form.id.value.indexOf(':') != -1 &&
link.indexOf(':') == -1){
link = ':' + link;
}
var so = link.length;
var eo = 0;
if(dw_linkwiz.val){
if(dw_linkwiz.val.open) {
so += dw_linkwiz.val.open.length;
link = dw_linkwiz.val.open+link;
}
link += '|';
so += 1;
if(stxt) {
link += stxt;
}
if(dw_linkwiz.val.close) {
link += dw_linkwiz.val.close;
eo = dw_linkwiz.val.close.length;
}
}
pasteText(sel,link,{startofs: so, endofs: eo});
dw_linkwiz.hide();
// reset the entry to the parent namespace
var externallinkpattern = new RegExp('^((f|ht)tps?:)?//', 'i'),
entry_value;
if (externallinkpattern.test(dw_linkwiz.$entry.val())) {
if (JSINFO.namespace) {
entry_value = JSINFO.namespace + ':';
} else {
entry_value = ''; //reset whole external links
}
} else {
entry_value = dw_linkwiz.$entry.val().replace(/[^:]*$/, '')
}
dw_linkwiz.$entry.val(entry_value);
},
/**
* Start the page/namespace lookup timer
*
* Calls autocomplete_exec when the timer runs out
*/
autocomplete: function(){
if(dw_linkwiz.timer !== null){
window.clearTimeout(dw_linkwiz.timer);
dw_linkwiz.timer = null;
}
dw_linkwiz.timer = window.setTimeout(dw_linkwiz.autocomplete_exec,350);
},
/**
* Executes the AJAX call for the page/namespace lookup
*/
autocomplete_exec: function(){
var $res = jQuery(dw_linkwiz.result);
dw_linkwiz.deselect();
$res.html('')
.load(
DOKU_BASE + 'lib/exe/ajax.php',
{
call: 'linkwiz',
q: dw_linkwiz.$entry.val()
}
);
},
/**
* Show the link wizard
*/
show: function(){
dw_linkwiz.selection = DWgetSelection(dw_linkwiz.textArea);
dw_linkwiz.$wiz.show();
dw_linkwiz.$entry.focus();
dw_linkwiz.autocomplete();
// Move the cursor to the end of the input
var temp = dw_linkwiz.$entry.val();
dw_linkwiz.$entry.val('');
dw_linkwiz.$entry.val(temp);
},
/**
* Hide the link wizard
*/
hide: function(){
dw_linkwiz.$wiz.hide();
dw_linkwiz.textArea.focus();
},
/**
* Toggle the link wizard
*/
toggle: function(){
if(dw_linkwiz.$wiz.css('display') == 'none'){
dw_linkwiz.show();
}else{
dw_linkwiz.hide();
}
}
};
/* XXXXXXXXXX end of lib/scripts/linkwiz.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/media.js XXXXXXXXXX */
/**
* JavaScript functionality for the media management popup
*
* @author Andreas Gohr
* @author Pierre Spring
*/
var dw_mediamanager = {
keepopen: false,
hide: false,
popup: false,
display: false,
ext: false,
$popup: null,
// Image insertion opts
align: false,
link: false,
size: false,
forbidden_opts: {},
// File list options
view_opts: {list: false, sort: false},
layout_width: 0,
// The minimum height of the full-screen mediamanager in px
minHeights: {thumbs: 200, rows: 100},
init: function () {
var $content, $tree;
$content = jQuery('#media__content');
$tree = jQuery('#media__tree');
if (!$tree.length) return;
dw_mediamanager.prepare_content($content);
dw_mediamanager.attachoptions();
dw_mediamanager.initpopup();
// add the action to autofill the "upload as" field
$content
.on('change', '#upload__file', dw_mediamanager.suggest)
// Attach the image selector action to all links
.on('click', 'a.select', dw_mediamanager.select)
// Attach deletion confirmation dialog to the delete buttons
.on('click', '#media__content a.btn_media_delete', dw_mediamanager.confirmattach)
.on('submit', '#mediamanager__done_form', dw_mediamanager.list);
$tree.dw_tree({
toggle_selector: 'img',
load_data: function (show_sublist, $clicky) {
// get the enclosed link (is always the first one)
var $link = $clicky.parent().find('div.li a.idx_dir');
jQuery.post(
DOKU_BASE + 'lib/exe/ajax.php',
$link[0].search.substr(1) + '&call=medians',
show_sublist,
'html'
);
},
toggle_display: function ($clicky, opening) {
$clicky.attr('src', DOKU_BASE + 'lib/images/' + (opening ? 'minus' : 'plus') + '.gif');
}
});
$tree.on('click', 'a', dw_mediamanager.list);
// Init view property
dw_mediamanager.set_fileview_list();
dw_mediamanager.init_options();
dw_mediamanager.image_diff();
dw_mediamanager.init_ajax_uploader();
// changing opened tab in the file list panel
var $page = jQuery('#mediamanager__page');
$page.find('div.filelist')
.on('click', 'ul.tabs a', dw_mediamanager.list)
// loading file details
.on('click', 'div.panelContent a', dw_mediamanager.details)
// search form
.on('submit', '#dw__mediasearch', dw_mediamanager.list)
// "upload as" field autofill
.on('change', '#upload__file', dw_mediamanager.suggest)
// uploaded images
.on('click', '.qq-upload-file a', dw_mediamanager.details);
// changing opened tab in the file details panel
$page.find('div.file')
.on('click', 'ul.tabs a', dw_mediamanager.details)
// "update new version" button
.on('submit', '#mediamanager__btn_update', dw_mediamanager.list)
// revisions form
.on('submit', '#page__revisions', dw_mediamanager.details)
.on('click', '#page__revisions a', dw_mediamanager.details)
// meta edit form
.on('submit', '#mediamanager__save_meta', dw_mediamanager.details)
// delete button
.on('submit', '#mediamanager__btn_delete', dw_mediamanager.details)
// "restore this version" button
.on('submit', '#mediamanager__btn_restore', dw_mediamanager.details)
// less/more recent buttons in media revisions form
.on('submit', '.btn_newer, .btn_older', dw_mediamanager.details);
dw_mediamanager.update_resizable();
dw_mediamanager.layout_width = $page.width();
jQuery(window).resize(dw_mediamanager.window_resize);
},
init_options: function () {
var $options = jQuery('div.filelist div.panelHeader form.options'),
$listType, $sortBy, $both;
if ($options.length === 0) {
return;
}
$listType = $options.find('li.listType');
$sortBy = $options.find('li.sortBy');
$both = $listType.add($sortBy);
// Remove the submit button
$options.find('button[type=submit]').parent().hide();
// Prepare HTML for jQuery UI buttonset
$both.find('label').each(function () {
var $this = jQuery(this);
$this.children('input').appendTo($this.parent());
});
// Init buttonset
$both.find("input[type='radio']").checkboxradio({icon: false});
$both.controlgroup();
// Change handlers
$listType.children('input').change(function () {
dw_mediamanager.set_fileview_list();
});
$sortBy.children('input').change(function (event) {
dw_mediamanager.set_fileview_sort();
dw_mediamanager.list.call(jQuery('#dw__mediasearch')[0] || this, event);
});
},
/**
* build the popup window
*
* @author Dominik Eckelmann
*/
initpopup: function () {
var opts, $insp, $insbtn;
dw_mediamanager.$popup = jQuery(document.createElement('div'))
.attr('id', 'media__popup_content')
.dialog({
autoOpen: false, width: 280, modal: true,
draggable: true, title: LANG.mediatitle,
resizable: false
});
opts = [
{
id: 'link', label: LANG.mediatarget,
btns: ['lnk', 'direct', 'nolnk', 'displaylnk']
},
{
id: 'align', label: LANG.mediaalign,
btns: ['noalign', 'left', 'center', 'right']
},
{
id: 'size', label: LANG.mediasize,
btns: ['small', 'medium', 'large', 'original']
}
];
jQuery.each(opts, function (_, opt) {
var $p, $l;
$p = jQuery(document.createElement('p'))
.attr('id', 'media__' + opt.id);
if (dw_mediamanager.display === "2") {
$p.hide();
}
$l = jQuery(document.createElement('label'))
.text(opt.label);
$p.append($l);
jQuery.each(opt.btns, function (i, text) {
var $btn, $img;
$btn = jQuery(document.createElement('button'))
.addClass('button')
.attr('id', "media__" + opt.id + "btn" + (i + 1))
.attr('title', LANG['media' + text])
.click(bind(dw_mediamanager.setOpt, opt.id));
$img = jQuery(document.createElement('img'))
.attr('src', DOKU_BASE + 'lib/images/media_' + opt.id + '_' + text + '.png');
$btn.append($img);
$p.append($btn);
});
dw_mediamanager.$popup.append($p);
});
// insert button
$insp = jQuery(document.createElement('p'));
dw_mediamanager.$popup.append($insp);
$insbtn = jQuery(document.createElement('input'))
.attr('id', 'media__sendbtn')
.attr('type', 'button')
.addClass('button')
.val(LANG.mediainsert);
$insp.append($insbtn);
},
/**
* Insert the clicked image into the opener's textarea
*
* @author Andreas Gohr
* @author Dominik Eckelmann
* @author Pierre Spring
*/
insert: function (id) {
var opts, cb, edid, s;
// set syntax options
dw_mediamanager.$popup.dialog('close');
opts = '';
if ({img: 1, swf: 1}[dw_mediamanager.ext] === 1) {
if (dw_mediamanager.link === '4') {
opts = '?linkonly';
} else {
if (dw_mediamanager.link === "3" && dw_mediamanager.ext === 'img') {
opts = '?nolink';
} else if (dw_mediamanager.link === "2" && dw_mediamanager.ext === 'img') {
opts = '?direct';
}
s = parseInt(dw_mediamanager.size, 10);
var size = s * 200;
if (s && s >= 1 && s < 4) {
opts += (opts.length) ? '&' : '?';
opts += size;
if (dw_mediamanager.ext === 'swf') {
switch (s) {
case 1:
opts += 'x62';
break;
case 2:
opts += 'x123';
break;
case 3:
opts += 'x185';
break;
}
}
}
}
}
edid = String.prototype.match.call(document.location, /&edid=([^&]+)/);
edid = edid ? edid[1] : 'wiki__text';
cb = String.prototype.match.call(document.location, /&onselect=([^&]+)/);
cb = cb ? cb[1].replace(/[^\w]+/, '') : 'dw_mediamanager_item_select';
opener[cb](edid, id, opts, dw_mediamanager.align);
if (!dw_mediamanager.keepopen) {
window.close();
}
opener.focus();
return false;
},
/**
* Prefills the wikiname.
*
* @author Andreas Gohr
*/
suggest: function () {
var $file, $name, text;
$file = jQuery(this);
$name = jQuery('#upload__name');
if ($name.val() != '') return;
if (!$file.length || !$name.length) {
return;
}
text = $file.val();
text = text.substr(text.lastIndexOf('/') + 1);
text = text.substr(text.lastIndexOf('\\') + 1);
$name.val(text);
},
/**
* list the content of a namespace using AJAX
*
* @author Andreas Gohr
* @author Pierre Spring
*/
list: function (event) {
var $link, $content, params;
if (event) {
event.preventDefault();
}
jQuery('div.success, div.info, div.error, div.notify').remove();
$link = jQuery(this);
//popup
$content = jQuery('#media__content');
if ($content.length === 0) {
//fullscreen media manager
$content = jQuery('div.filelist');
if ($link.hasClass('idx_dir')) {
//changing namespace
jQuery('div.file').empty();
jQuery('div.namespaces .selected').removeClass('selected');
$link.addClass('selected');
}
}
params = 'call=medialist&';
if ($link[0].search) {
params += $link[0].search.substr(1);
} else if ($link.is('form')) {
params += dw_mediamanager.form_params($link);
} else if ($link.closest('form').length > 0) {
params += dw_mediamanager.form_params($link.closest('form'));
}
// fetch the subtree
dw_mediamanager.update_content($content, params);
},
/**
* Returns form parameters
*
* @author Kate Arzamastseva
*/
form_params: function ($form) {
if (!$form.length) return;
var action = '';
var i = $form[0].action.indexOf('?');
if (i >= 0) {
action = $form[0].action.substr(i + 1);
}
return action + '&' + $form.serialize();
},
set_fileview_list: function (new_type) {
dw_mediamanager.set_fileview_opt(['list', 'listType', function (new_type) {
jQuery('div.filelist div.panelContent ul')
.toggleClass('rows', new_type === 'rows')
.toggleClass('thumbs', new_type === 'thumbs');
}], new_type);
// FIXME: Move to onchange handler (opt[2])?
dw_mediamanager.resize();
},
set_fileview_sort: function (new_sort) {
dw_mediamanager.set_fileview_opt(['sort', 'sortBy', function (new_sort) {
// FIXME
}], new_sort);
},
set_fileview_opt: function (opt, new_val) {
if (typeof new_val === 'undefined') {
new_val = jQuery('form.options li.' + opt[1] + ' input')
.filter(':checked').val();
// if new_val is still undefined (because form.options is not in active tab), set to most spacious option
if (typeof new_val === 'undefined') {
new_val = 'thumbs';
}
}
if (new_val !== dw_mediamanager.view_opts[opt[0]]) {
opt[2](new_val);
DokuCookie.setValue(opt[0], new_val);
dw_mediamanager.view_opts[opt[0]] = new_val;
}
},
/**
* Lists the content of the right column (image details) using AJAX
*
* @author Kate Arzamastseva
*/
details: function (event) {
var $link, $content, params, update_list;
$link = jQuery(this);
event.preventDefault();
jQuery('div.success, div.info, div.error, div.notify').remove();
if ($link[0].id == 'mediamanager__btn_delete' && !confirm(LANG.del_confirm)) {
return false;
}
if ($link[0].id == 'mediamanager__btn_restore' && !confirm(LANG.restore_confirm)) {
return false;
}
$content = jQuery('div.file');
params = 'call=mediadetails&';
if ($link[0].search) {
params += $link[0].search.substr(1);
} else if ($link.is('form')) {
params += dw_mediamanager.form_params($link);
} else if ($link.closest('form').length > 0) {
params += dw_mediamanager.form_params($link.closest('form'));
}
update_list = ($link[0].id == 'mediamanager__btn_delete' ||
$link[0].id == 'mediamanager__btn_restore');
dw_mediamanager.update_content($content, params, update_list);
},
update_content: function ($content, params, update_list) {
var $container;
jQuery.post(
DOKU_BASE + 'lib/exe/ajax.php',
params,
function (data) {
dw_mediamanager.$resizables().resizable('destroy');
if (update_list) {
dw_mediamanager.list.call(jQuery('#mediamanager__page').find('form.options button[type="submit"]')[0]);
}
$content.html(data);
dw_mediamanager.prepare_content($content);
dw_mediamanager.updatehide();
dw_mediamanager.update_resizable();
dw_behaviour.revisionBoxHandler();
// Make sure that the list view style stays the same
dw_mediamanager.set_fileview_list(dw_mediamanager.view_opts.list);
dw_mediamanager.image_diff();
dw_mediamanager.init_ajax_uploader();
dw_mediamanager.init_options();
},
'html'
);
$container = $content.find('div.panelContent');
if ($container.length === 0) {
$container = $content;
}
$container.html('');
},
window_resize: function () {
dw_mediamanager.resize();
dw_mediamanager.opacity_slider();
dw_mediamanager.portions_slider();
},
$resizables: function () {
return jQuery('#mediamanager__page').find('div.namespaces, div.filelist');
},
/**
* Updates mediamanager layout
*
* @author Kate Arzamastseva
*/
update_resizable: function () {
var $resizables = dw_mediamanager.$resizables();
$resizables.resizable({
handles: (jQuery('html[dir=rtl]').length ? 'w' : 'e'),
resize: function (event, ui) {
var $page = jQuery('#mediamanager__page');
var widthFull = $page.width();
var widthResizables = 0;
$resizables.each(function () {
widthResizables += jQuery(this).width();
});
var $filePanel = $page.find('div.panel.file');
// set max width of resizable column
var widthOtherResizable = widthResizables - jQuery(this).width();
var minWidthNonResizable = parseFloat($filePanel.css("min-width"));
var maxWidth = widthFull - (widthOtherResizable + minWidthNonResizable) - 1;
$resizables.resizable("option", "maxWidth", maxWidth);
// width of file panel in % = 100% - width of resizables in %
// this calculates with 99.9 and not 100 to overcome rounding errors
var relWidthNonResizable = 99.9 - (100 * widthResizables / widthFull);
// set width of file panel
$filePanel.width(relWidthNonResizable + '%');
dw_mediamanager.resize();
dw_mediamanager.opacity_slider();
dw_mediamanager.portions_slider();
}
});
dw_mediamanager.resize();
},
resize: function () {
var $contents = jQuery('#mediamanager__page').find('div.panelContent'),
height = jQuery(window).height() - jQuery(document.body).height() +
Math.max.apply(null, jQuery.map($contents, function (v) {
return jQuery(v).height();
}));
// If the screen is too small, don’t try to resize
if (height < dw_mediamanager.minHeights[dw_mediamanager.view_opts.list]) {
$contents.add(dw_mediamanager.$resizables()).height('auto');
} else {
$contents.height(height);
dw_mediamanager.$resizables().each(function () {
var $this = jQuery(this);
$this.height(height + $this.find('div.panelContent').offset().top - $this.offset().top);
});
}
},
/**
* Prints 'select' for image difference representation type
*
* @author Kate Arzamastseva
*/
image_diff: function () {
if (jQuery('#mediamanager__difftype').length) return;
var $form = jQuery('#mediamanager__form_diffview');
if (!$form.length) return;
var $label = jQuery(document.createElement('label'));
$label.append('' + LANG.media_diff + ' ');
var $select = jQuery(document.createElement('select'))
.attr('id', 'mediamanager__difftype')
.attr('name', 'difftype')
.change(dw_mediamanager.change_diff_type);
$select.append(new Option(LANG.media_diff_both, "both"));
$select.append(new Option(LANG.media_diff_opacity, "opacity"));
$select.append(new Option(LANG.media_diff_portions, "portions"));
$label.append($select);
$form.append($label);
// for IE
var select = document.getElementById('mediamanager__difftype');
select.options[0].text = LANG.media_diff_both;
select.options[1].text = LANG.media_diff_opacity;
select.options[2].text = LANG.media_diff_portions;
},
/**
* Handles selection of image difference representation type
*
* @author Kate Arzamastseva
*/
change_diff_type: function () {
var $select = jQuery('#mediamanager__difftype');
var $content = jQuery('#mediamanager__diff');
var params = dw_mediamanager.form_params($select.closest('form')) + '&call=mediadiff';
jQuery.post(
DOKU_BASE + 'lib/exe/ajax.php',
params,
function (data) {
$content.html(data);
dw_mediamanager.portions_slider();
dw_mediamanager.opacity_slider();
},
'html'
);
},
/**
* Sets options for opacity diff slider
*
* @author Kate Arzamastseva
*/
opacity_slider: function () {
var $diff = jQuery("#mediamanager__diff");
var $slider = $diff.find("div.slider");
if (!$slider.length) return;
var $image = $diff.find('div.imageDiff.opacity div.image1 img');
if (!$image.length) return;
$slider.width($image.width() - 20);
$slider.slider();
$slider.slider("option", "min", 0);
$slider.slider("option", "max", 0.999);
$slider.slider("option", "step", 0.001);
$slider.slider("option", "value", 0.5);
$slider.on("slide", function (event, ui) {
jQuery('#mediamanager__diff').find('div.imageDiff.opacity div.image2 img').css({opacity: $slider.slider("option", "value")});
});
},
/**
* Sets options for red line diff slider
*
* @author Kate Arzamastseva
*/
portions_slider: function () {
var $diff = jQuery("#mediamanager__diff");
if (!$diff.length) return;
var $image1 = $diff.find('div.imageDiff.portions div.image1 img');
var $image2 = $diff.find('div.imageDiff.portions div.image2 img');
if (!$image1.length || !$image2.length) return;
$diff.width('100%');
$image2.parent().width('97%');
$image1.width('100%');
$image2.width('100%');
if ($image1.width() < $diff.width()) {
$diff.width($image1.width());
}
$image2.parent().width('50%');
$image2.width($image1.width());
$image1.width($image1.width());
var $slider = $diff.find("div.slider");
if (!$slider.length) return;
$slider.width($image1.width() - 20);
$slider.slider();
$slider.slider("option", "min", 0);
$slider.slider("option", "max", 97);
$slider.slider("option", "step", 1);
$slider.slider("option", "value", 50);
$slider.on("slide", function (event, ui) {
jQuery('#mediamanager__diff').find('div.imageDiff.portions div.image2').css({width: $slider.slider("option", "value") + '%'});
});
},
/**
* Parse a URI query string to an associative array
*
* @author Kate Arzamastseva
*/
params_toarray: function (str) {
var vars = [], hash;
var hashes = str.split('&');
for (var i = 0; i < hashes.length; i++) {
hash = hashes[i].split('=');
vars[decodeURIComponent(hash[0])] = decodeURIComponent(hash[1]);
}
return vars;
},
init_ajax_uploader: function () {
if (!jQuery('#mediamanager__uploader').length) return;
if (jQuery('.qq-upload-list').length) return;
var params = dw_mediamanager.form_params(jQuery('#dw__upload')) + '&call=mediaupload';
params = dw_mediamanager.params_toarray(params);
var uploader = new qq.FileUploaderExtended({
element: document.getElementById('mediamanager__uploader'),
action: DOKU_BASE + 'lib/exe/ajax.php',
params: params
});
},
prepare_content: function ($content) {
// hide syntax example
$content.find('div.example:visible').hide();
},
/**
* shows the popup for a image link
*/
select: function (event) {
var $link, id, dot, ext;
event.preventDefault();
$link = jQuery(this);
id = $link.attr('id').substr(2);
if (!opener) {
// if we don't run in popup display example
// the id's are a bit wierd and jQuery('#ex_wiki_dokuwiki-128.png')
// will not be found by Sizzle (the CSS Selector Engine
// used by jQuery), hence the document.getElementById() call
jQuery(document.getElementById('ex_' + id.replace(/:/g, '_').replace(/^_/, ''))).dw_toggle();
return;
}
dw_mediamanager.ext = false;
dot = id.lastIndexOf(".");
if (-1 === dot) {
dw_mediamanager.insert(id);
return;
}
ext = id.substr(dot);
if ({'.jpg': 1, '.jpeg': 1, '.png': 1, '.gif': 1, '.swf': 1}[ext] !== 1) {
dw_mediamanager.insert(id);
return;
}
// remove old callback from the insert button and set the new one.
var $sendbtn = jQuery('#media__sendbtn');
$sendbtn.off().click(bind(dw_mediamanager.insert, id));
dw_mediamanager.unforbid('ext');
if (ext === '.swf') {
dw_mediamanager.ext = 'swf';
dw_mediamanager.forbid('ext', {
link: ['1', '2'],
size: ['4']
});
} else {
dw_mediamanager.ext = 'img';
}
// Set to defaults
dw_mediamanager.setOpt('link');
dw_mediamanager.setOpt('align');
dw_mediamanager.setOpt('size');
// toggle buttons for detail and linked image, original size
jQuery('#media__linkbtn1, #media__linkbtn2, #media__sizebtn4')
.toggle(dw_mediamanager.ext === 'img');
dw_mediamanager.$popup.dialog('open');
$sendbtn.focus();
},
/**
* Deletion confirmation dialog to the delete buttons.
*
* @author Michael Klier
* @author Pierre Spring
*/
confirmattach: function (e) {
if (!confirm(LANG.del_confirm + "\n" + jQuery(this).attr('title'))) {
e.preventDefault();
}
},
/**
* Creates checkboxes for additional options
*
* @author Andreas Gohr
* @author Pierre Spring
*/
attachoptions: function () {
var $obj, opts;
$obj = jQuery('#media__opts');
if ($obj.length === 0) {
return;
}
opts = [];
// keep open
if (opener) {
opts.push(['keepopen', 'keepopen']);
}
opts.push(['hide', 'hidedetails']);
jQuery.each(opts,
function (_, opt) {
var $box, $lbl;
$box = jQuery(document.createElement('input'))
.attr('type', 'checkbox')
.attr('id', 'media__' + opt[0])
.click(bind(dw_mediamanager.toggleOption, opt[0]));
if (DokuCookie.getValue(opt[0])) {
$box.prop('checked', true);
dw_mediamanager[opt[0]] = true;
}
$lbl = jQuery(document.createElement('label'))
.attr('for', 'media__' + opt[0])
.text(LANG[opt[1]]);
$obj.append($box, $lbl, document.createElement('br'));
});
dw_mediamanager.updatehide();
},
/**
* Generalized toggler
*
* @author Pierre Spring
*/
toggleOption: function (variable) {
if (jQuery(this).prop('checked')) {
DokuCookie.setValue(variable, 1);
dw_mediamanager[variable] = true;
} else {
DokuCookie.setValue(variable, '');
dw_mediamanager[variable] = false;
}
if (variable === 'hide') {
dw_mediamanager.updatehide();
}
},
/**
* Sets the visibility of the image details accordingly to the
* chosen hide state
*
* @author Andreas Gohr
*/
updatehide: function () {
jQuery('#media__content').find('div.detail').dw_toggle(!dw_mediamanager.hide);
},
/**
* set media insertion option
*
* @author Dominik Eckelmann
*/
setOpt: function (opt, e) {
var val, i;
if (typeof e !== 'undefined') {
val = this.id.substring(this.id.length - 1);
} else {
val = dw_mediamanager.getOpt(opt);
}
if (val === false) {
DokuCookie.setValue(opt, '');
dw_mediamanager[opt] = false;
return;
}
if (opt === 'link') {
if (val !== '4' && dw_mediamanager.link === '4') {
dw_mediamanager.unforbid('linkonly');
dw_mediamanager.setOpt('align');
dw_mediamanager.setOpt('size');
} else if (val === '4') {
dw_mediamanager.forbid('linkonly', {align: false, size: false});
}
jQuery("#media__size, #media__align").dw_toggle(val !== '4');
}
DokuCookie.setValue(opt, val);
dw_mediamanager[opt] = val;
for (i = 1; i <= 4; i++) {
jQuery("#media__" + opt + "btn" + i).removeClass('selected');
}
jQuery('#media__' + opt + 'btn' + val).addClass('selected');
},
unforbid: function (group) {
delete dw_mediamanager.forbidden_opts[group];
},
forbid: function (group, forbids) {
dw_mediamanager.forbidden_opts[group] = forbids;
},
allowedOpt: function (opt, val) {
var ret = true;
jQuery.each(dw_mediamanager.forbidden_opts,
function (_, forbids) {
ret = forbids[opt] !== false &&
jQuery.inArray(val, forbids[opt]) === -1;
return ret;
});
return ret;
},
getOpt: function (opt) {
var allowed = bind(dw_mediamanager.allowedOpt, opt);
// Current value
if (dw_mediamanager[opt] !== false && allowed(dw_mediamanager[opt])) {
return dw_mediamanager[opt];
}
// From cookie
if (DokuCookie.getValue(opt) && allowed(DokuCookie.getValue(opt))) {
return DokuCookie.getValue(opt);
}
// size default
if (opt === 'size' && allowed('2')) {
return '2';
}
// Whatever is allowed, and be it false
return jQuery.grep(['1', '2', '3', '4'], allowed)[0] || false;
}
};
/**
* Default implementation for the media manager's select action
*
* Can be overriden with the onselect URL parameter. Is called on the opener context
*
* @param {string} edid
* @param {string} mediaid
* @param {string} opts
* @param {string} align [none, left, center, right]
*/
function dw_mediamanager_item_select(edid, mediaid, opts, align) {
var alignleft = '';
var alignright = '';
if (align !== '1') {
alignleft = align === '2' ? '' : ' ';
alignright = align === '4' ? '' : ' ';
}
insertTags(edid, '{{' + alignleft + mediaid + opts + alignright + '|', '}}', '');
}
jQuery(dw_mediamanager.init);
/* XXXXXXXXXX end of lib/scripts/media.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/compatibility.js XXXXXXXXXX */
/**
* Mark a JavaScript function as deprecated
*
* This will print a warning to the JavaScript console (if available) in
* Firebug and Chrome and a stack trace (if available) to easily locate the
* problematic function call.
*
* @param msg optional message to print
*/
function DEPRECATED(msg){
if(!window.console) return;
if(!msg) msg = '';
var func;
if(arguments.callee) func = arguments.callee.caller.name;
if(func) func = ' '+func+'()';
var line = 'DEPRECATED function call'+func+'. '+msg;
if(console.warn){
console.warn(line);
}else{
console.log(line);
}
if(console.trace) console.trace();
}
/**
* Construct a wrapper function for deprecated function names
*
* This function returns a wrapper function which just calls DEPRECATED
* and the new function.
*
* @param func The new function
* @param context Optional; The context (`this`) of the call
*/
function DEPRECATED_WRAP(func, context) {
return function () {
DEPRECATED();
return func.apply(context || this, arguments);
};
}
/* XXXXXXXXXX end of lib/scripts/compatibility.js XXXXXXXXXX */
/* XXXXXXXXXX begin of lib/scripts/behaviour.js XXXXXXXXXX */
/**
* Hides elements with a slide animation
*
* @param {function} fn optional callback to run after hiding
* @param {bool} noaria supress aria-expanded state setting
* @author Adrian Lang
*/
jQuery.fn.dw_hide = function(fn, noaria) {
if(!noaria) this.attr('aria-expanded', 'false');
return this.slideUp('fast', fn);
};
/**
* Unhides elements with a slide animation
*
* @param {function} fn optional callback to run after hiding
* @param {bool} noaria supress aria-expanded state setting
* @author Adrian Lang
*/
jQuery.fn.dw_show = function(fn, noaria) {
if(!noaria) this.attr('aria-expanded', 'true');
return this.slideDown('fast', fn);
};
/**
* Toggles visibility of an element using a slide element
*
* @param {bool} state the current state of the element (optional)
* @param {function} fn callback after the state has been toggled
* @param {bool} noaria supress aria-expanded state setting
*/
jQuery.fn.dw_toggle = function(state, fn, noaria) {
return this.each(function() {
var $this = jQuery(this);
if (typeof state === 'undefined') {
state = $this.is(':hidden');
}
$this[state ? "dw_show" : "dw_hide" ](fn, noaria);
});
};
/**
* Automatic behaviours
*
* This class wraps various JavaScript functionalities that are triggered
* automatically whenever a certain object is in the DOM or a certain CSS
* class was found
*/
var dw_behaviour = {
init: function(){
dw_behaviour.focusMarker();
dw_behaviour.scrollToMarker();
dw_behaviour.removeHighlightOnClick();
dw_behaviour.quickSelect();
dw_behaviour.checkWindowsShares();
dw_behaviour.subscription();
dw_behaviour.revisionBoxHandler();
jQuery(document).on('click','#page__revisions input[type=checkbox]',
dw_behaviour.revisionBoxHandler
);
jQuery('.bounce').effect('bounce', {times:10}, 2000 );
},
/**
* Looks for an element with the ID scroll__here at scrolls to it
*/
scrollToMarker: function(){
var $obj = jQuery('#scroll__here');
if($obj.length) {
if($obj.offset().top != 0) {
jQuery('html, body').animate({
scrollTop: $obj.offset().top - 100
}, 500);
} else {
// hidden object have no offset but can still be scrolled into view
$obj[0].scrollIntoView();
}
}
},
/**
* Looks for an element with the ID focus__this at sets focus to it
*/
focusMarker: function(){
jQuery('#focus__this').focus();
},
/**
* Remove all search highlighting when clicking on a highlighted term
*/
removeHighlightOnClick: function(){
jQuery('span.search_hit').click(
function(e){
jQuery(e.target).removeClass('search_hit', 1000);
}
);
},
/**
* Autosubmit quick select forms
*
* When a