(function (w) { w.Typecho = { insertFileToEditor : function () {} }; })(window); (function ($) { // 下拉菜单插件 $.fn.dropdownMenu = function (options) { this.each(function () { var menu = this, s = $.extend({ menuEl : null, btnEl : null }, options); $(s.btnEl, menu).click(function () { var t = $(this); t.toggleClass('active'); $(s.menuEl, menu).toggle(); return false; }); }); }; // 表格选择插件 $.fn.tableSelectable = function (options) { var table = this, s = $.extend({ checkEl : null, rowEl : null, selectAllEl : null, actionEl : null }, options); function clickRow (t) { var t = $(t), check = $(s.checkEl, t), checked = check.prop('checked'); if (!check.length) { return; } check.prop('checked', !checked); if (checked) { t.removeClass('checked'); } else { t.addClass('checked'); } } $(s.rowEl, this).each(function () { $(s.checkEl, this).click(function (e) { clickRow($(this).parents(s.rowEl)); }); $('input[type=text],input[type=password],textarea,input[type=submit],input[type=button],a,button').click(function (e) { e.stopPropagation(); }); }).click(function () { clickRow(this); }); $(s.selectAllEl).click(function () { var t = $(this), checked = t.prop('checked'); if (checked) { $(s.rowEl, table).each(function () { $(s.checkEl, this).prop('checked', true); }).addClass('checked'); } else { $(s.rowEl, table).each(function () { $(s.checkEl, this).prop('checked', false); }).removeClass('checked'); } }); $(s.actionEl).click(function () { var t = $(this), lang = t.attr('lang'); if (!lang || confirm(lang)) { table.parents('form').attr('action', t.attr('href')).submit(); } return false; }); }; $.fn.fileUpload = function (options) { var s = $.extend({ url : null, onUpload : null, onComplete : null, onError : null, types : null, name : 'file', typesError : 'file type error', single : false }, options), p = this.parent().css('position', 'relative'), input = $('').css({ opacity : 0, cursor : 'pointer', position : 'absolute', width : this.outerWidth(), height : this.outerHeight, left : this.offset().left - p.offset().left, top : this.offset().top - p.offset().top }).insertAfter(this), queue = {}, prefix = 'queue-', index = 0, types = []; window.fileUploadComplete = function (id, url, data) { if (s.single) { input.prop('disabled', false); } if (!!id && queue[id]) { queue[id].remove(); delete queue[id]; if (s.onComplete) { s.onComplete.call(input.get(0), id, url, data); } } }; window.fileUploadError = function (id, word) { if (s.single) { input.prop('disabled', false); } if (!!id && queue[id]) { queue[id].remove(); delete queue[id]; if (s.onError) { s.onError.call(input.get(0), id, word); } } }; if (!!s.types) { var list = s.types.split(';'); for (var i = 0; i < list.length; i ++) { var parts = list[i].split('.'); parts.shift(); types.push('.' + parts.join('.')); } } function upload (frame, id) { var form = $('
'), replace = input.clone(true).val(''), io = frame[0], doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document; replace.insertBefore(input); form.append(input); $('body', doc).html('').append(form); input = replace; form.submit(); } function checkTypes (file) { if (!types.length) { return true; } for (var i = 0; i < types.length; i ++) { var ext = types[i]; if (file.length <= ext.length) { continue; } if (ext == file.substring(file.length - ext.length)) { return true; } } return false; } input.change(function () { var t = $(this), file = t.val(); if (!file) { return; } else { file = file.split(/\\|\//).pop(); } if (!checkTypes(file)) { alert(s.typesError.replace('%s', file)); return; } if (s.single) { t.prop('disabled', true); } var id = prefix + index; index ++; queue[id] = $('').appendTo(document.body); if (s.onUpload) { s.onUpload.call(this, file, id); } upload(queue[id], id); }); }; })($); /** * TableDnD plug-in for JQuery, allows you to drag and drop table rows * You can set up various options to control how the system will work * Copyright © Denis Howlett * Licensed like jQuery, see http://docs.jquery.com/License. * * Configuration options: * * onDragStyle * This is the style that is assigned to the row during drag. There are limitations to the styles that can be * associated with a row (such as you can't assign a border—well you can, but it won't be * displayed). (So instead consider using onDragClass.) The CSS style to apply is specified as * a map (as used in the jQuery css(...) function). * onDropStyle * This is the style that is assigned to the row when it is dropped. As for onDragStyle, there are limitations * to what you can do. Also this replaces the original style, so again consider using onDragClass which * is simply added and then removed on drop. * onDragClass * This class is added for the duration of the drag and then removed when the row is dropped. It is more * flexible than using onDragStyle since it can be inherited by the row cells and other content. The default * is class is tDnD_whileDrag. So to use the default, simply customise this CSS class in your * stylesheet. * onDrop * Pass a function that will be called when the row is dropped. The function takes 2 parameters: the table * and the row that was dropped. You can work out the new order of the rows by using * table.rows. * onDragStart * Pass a function that will be called when the user starts dragging. The function takes 2 parameters: the * table and the row which the user has started to drag. * onAllowDrop * Pass a function that will be called as a row is over another row. If the function returns true, allow * dropping on that row, otherwise not. The function takes 2 parameters: the dragged row and the row under * the cursor. It returns a boolean: true allows the drop, false doesn't allow it. * scrollAmount * This is the number of pixels to scroll if the user moves the mouse cursor to the top or bottom of the * window. The page should automatically scroll up or down as appropriate (tested in IE6, IE7, Safari, FF2, * FF3 beta) * * Other ways to control behaviour: * * Add class="nodrop" to any rows for which you don't want to allow dropping, and class="nodrag" to any rows * that you don't want to be draggable. * * Inside the onDrop method you can also call $.tableDnD.serialize() this returns a string of the form * []=&[]= so that you can send this back to the server. The table must have * an ID as must all the rows. * * Known problems: * - Auto-scoll has some problems with IE7 (it scrolls even when it shouldn't), work-around: set scrollAmount to 0 * * Version 0.2: 2008-02-20 First public version * Version 0.3: 2008-02-07 Added onDragStart option * Made the scroll amount configurable (default is 5 as before) * Version 0.4: 2008-03-15 Changed the noDrag/noDrop attributes to nodrag/nodrop classes * Added onAllowDrop to control dropping * Fixed a bug which meant that you couldn't set the scroll amount in both directions * Added serialise method */ (function (jQuery) { jQuery.tableDnD = { /** Keep hold of the current table being dragged */ currentTable : null, /** Keep hold of the current drag object if any */ dragObject: null, /** The current mouse offset */ mouseOffset: null, /** Remember the old value of Y so that we don't do too much processing */ oldY: 0, /** Actually build the structure */ build: function(options) { // Make sure options exists options = options || {}; // Set up the defaults if any this.each(function() { // Remember the options this.tableDnDConfig = { onDragStyle: options.onDragStyle, onDropStyle: options.onDropStyle, // Add in the default class for whileDragging onDragClass: options.onDragClass ? options.onDragClass : "tDnD_whileDrag", onDrop: options.onDrop, onDragStart: options.onDragStart, scrollAmount: options.scrollAmount ? options.scrollAmount : 5 }; // Now make the rows draggable jQuery.tableDnD.makeDraggable(this); // fix chrome border bug if (0 == $('tfoot', this).length && 0 < $('thead', this).length) { var h = $('thead', this), count = $('th', h).length, f = $('').insertAfter(h), l = $('tr:last', this); if (l.parent().prop('tagName').toLowerCase() != 'tfoot') { var td = $('td', l), dh = td.height(); td.height(dh - f.outerHeight()); } } }); // Now we need to capture the mouse up and mouse move event // We can use bind so that we don't interfere with other event handlers jQuery(document) .bind('mousemove', jQuery.tableDnD.mousemove) .bind('mouseup', jQuery.tableDnD.mouseup); // Don't break the chain return this; }, /** This function makes all the rows on the table draggable apart from those marked as "NoDrag" */ makeDraggable: function(table) { // Now initialise the rows var rows = table.rows; //getElementsByTagName("tr") var config = table.tableDnDConfig; for (var i=0; i jQuery.tableDnD.oldY; // update the old value jQuery.tableDnD.oldY = y; // update the style to show we're dragging if (config.onDragClass) { dragObj.addClass(config.onDragClass); } else { dragObj.css(config.onDragStyle); } // If we're over a row then move the dragged row to there so that the user sees the // effect dynamically var currentRow = jQuery.tableDnD.findDropTargetRow(dragObj, y); if (currentRow) { // TODO worry about what happens when there are multiple TBODIES if (movingDown && jQuery.tableDnD.dragObject != currentRow) { jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow.nextSibling); } else if (! movingDown && jQuery.tableDnD.dragObject != currentRow) { jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow); } } } return false; }, /** We're only worried about the y position really, because we can only move rows up and down */ findDropTargetRow: function(draggedRow, y) { var rows = jQuery.tableDnD.currentTable.rows; for (var i=0; i rowY - rowHeight) && (y < (rowY + rowHeight))) { // that's the row we're over // If it's the same as the current row, ignore it if (row == draggedRow) {return null;} var config = jQuery.tableDnD.currentTable.tableDnDConfig; if (config.onAllowDrop) { if (config.onAllowDrop(draggedRow, row)) { return row; } else { return null; } } else { // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic) var nodrop = $(row).hasClass("nodrop"); if (! nodrop) { return row; } else { return null; } } return row; } } return null; }, mouseup: function(e) { if (jQuery.tableDnD.currentTable && jQuery.tableDnD.dragObject) { var droppedRow = jQuery.tableDnD.dragObject; var config = jQuery.tableDnD.currentTable.tableDnDConfig; // If we have a dragObject, then we need to release it, // The row will already have been moved to the right place so we just reset stuff if (config.onDragClass) { jQuery(droppedRow).removeClass(config.onDragClass); } else { jQuery(droppedRow).css(config.onDropStyle); } jQuery.tableDnD.dragObject = null; if (config.onDrop) { // Call the onDrop method if there is one config.onDrop(jQuery.tableDnD.currentTable, droppedRow); } jQuery.tableDnD.currentTable = null; // let go of the table too } }, serialize: function() { if (jQuery.tableDnD.currentTable) { var result = ""; var tableId = jQuery.tableDnD.currentTable.id; var rows = jQuery.tableDnD.currentTable.rows; for (var i=0; i 0) result += "&"; result += tableId + '[]=' + rows[i].id; } return result; } else { return "Error: No Table id set, you need to set an id on your table and every row"; } } } jQuery.fn.extend( { tableDnD : jQuery.tableDnD.build } ); })($); /*global jQuery:false, alert:false */ /* * Default text - jQuery plugin for html5 dragging files from desktop to browser * * Author: Weixi Yen * * Email: [Firstname][Lastname]@gmail.com * * Copyright (c) 2010 Resopollution * * Licensed under the MIT license: * http://www.opensource.org/licenses/mit-license.php * * Project home: * http://www.github.com/weixiyen/jquery-filedrop * * Version: 0.1.0 * * Features: * Allows sending of extra parameters with file. * Works with Firefox 3.6+ * Future-compliant with HTML5 spec (will work with Webkit browsers and IE9) * Usage: * See README at project homepage * */ ;(function($) { jQuery.event.props.push("dataTransfer"); var default_opts = { fallback_id: '', url: '', refresh: 1000, paramname: 'userfile', requestType: 'POST', // just in case you want to use another HTTP verb allowedfileextensions:[], allowedfiletypes:[], maxfiles: 25, // Ignored if queuefiles is set > 0 maxfilesize: 1, // MB file size limit queuefiles: 0, // Max files before queueing (for large volume uploads) queuewait: 200, // Queue wait time if full data: {}, headers: {}, drop: empty, dragStart: empty, dragEnter: empty, dragOver: empty, dragLeave: empty, docEnter: empty, docOver: empty, docLeave: empty, beforeEach: empty, afterAll: empty, rename: empty, error: function(err, file, i, status) { alert(err); }, uploadStarted: empty, uploadFinished: empty, progressUpdated: empty, globalProgressUpdated: empty, speedUpdated: empty }, errors = ["BrowserNotSupported", "TooManyFiles", "FileTooLarge", "FileTypeNotAllowed", "NotFound", "NotReadable", "AbortError", "ReadError", "FileExtensionNotAllowed"]; $.fn.filedrop = function(options) { var opts = $.extend({}, default_opts, options), global_progress = [], doc_leave_timer, stop_loop = false, files_count = 0, files; $('#' + opts.fallback_id).css({ display: 'none', width: 0, height: 0 }); this.on('drop', drop).on('dragstart', opts.dragStart).on('dragenter', dragEnter).on('dragover', dragOver).on('dragleave', dragLeave); $(document).on('drop', docDrop).on('dragenter', docEnter).on('dragover', docOver).on('dragleave', docLeave); this.on('click', function(e){ $('#' + opts.fallback_id).trigger(e); }); $('#' + opts.fallback_id).change(function(e) { opts.drop(e); files = e.target.files; files_count = files.length; upload(); }); function drop(e) { if( opts.drop.call(this, e) === false ) return false; if(!e.dataTransfer) return; files = e.dataTransfer.files; if (files === null || files === undefined || files.length === 0) { opts.error(errors[0]); return false; } files_count = files.length; upload(); e.preventDefault(); return false; } function getBuilder(filename, filedata, mime, boundary) { var dashdash = '--', crlf = '\r\n', builder = '', paramname = opts.paramname; if (opts.data) { var params = $.param(opts.data).replace(/\+/g, '%20').split(/&/); $.each(params, function() { var pair = this.split("=", 2), name = decodeURIComponent(pair[0]), val = decodeURIComponent(pair[1]); if (pair.length !== 2) { return; } builder += dashdash; builder += boundary; builder += crlf; builder += 'Content-Disposition: form-data; name="' + name + '"'; builder += crlf; builder += crlf; builder += val; builder += crlf; }); } if (jQuery.isFunction(paramname)){ paramname = paramname(filename); } builder += dashdash; builder += boundary; builder += crlf; builder += 'Content-Disposition: form-data; name="' + (paramname||"") + '"'; builder += '; filename="' + filename + '"'; builder += crlf; builder += 'Content-Type: ' + mime; builder += crlf; builder += crlf; builder += filedata; builder += crlf; builder += dashdash; builder += boundary; builder += dashdash; builder += crlf; return builder; } function progress(e) { if (e.lengthComputable) { var percentage = Math.round((e.loaded * 100) / e.total); if (this.currentProgress !== percentage) { this.currentProgress = percentage; opts.progressUpdated(this.index, this.file, this.currentProgress); global_progress[this.global_progress_index] = this.currentProgress; globalProgress(); var elapsed = new Date().getTime(); var diffTime = elapsed - this.currentStart; if (diffTime >= opts.refresh) { var diffData = e.loaded - this.startData; var speed = diffData / diffTime; // KB per second opts.speedUpdated(this.index, this.file, speed); this.startData = e.loaded; this.currentStart = elapsed; } } } } function globalProgress() { if (global_progress.length === 0) { return; } var total = 0, index; for (index in global_progress) { if(global_progress.hasOwnProperty(index)) { total = total + global_progress[index]; } } opts.globalProgressUpdated(Math.round(total / global_progress.length)); } // Respond to an upload function upload() { stop_loop = false; if (!files) { opts.error(errors[0]); return false; } if (opts.allowedfiletypes.push && opts.allowedfiletypes.length) { for(var fileIndex = files.length;fileIndex--;) { if(!files[fileIndex].type || $.inArray(files[fileIndex].type, opts.allowedfiletypes) < 0) { opts.error(errors[3], files[fileIndex]); return false; } } } if (opts.allowedfileextensions.push && opts.allowedfileextensions.length) { for(var fileIndex = files.length;fileIndex--;) { var allowedextension = false; for (i=0;i opts.maxfiles && opts.queuefiles === 0) { opts.error(errors[1]); return false; } // Define queues to manage upload process var workQueue = []; var processingQueue = []; var doneQueue = []; // Add everything to the workQueue for (var i = 0; i < files_count; i++) { workQueue.push(i); } // Helper function to enable pause of processing to wait // for in process queue to complete var pause = function(timeout) { setTimeout(process, timeout); return; }; // Process an upload, recursive var process = function() { var fileIndex; if (stop_loop) { return false; } // Check to see if are in queue mode if (opts.queuefiles > 0 && processingQueue.length >= opts.queuefiles) { return pause(opts.queuewait); } else { // Take first thing off work queue fileIndex = workQueue[0]; workQueue.splice(0, 1); // Add to processing queue processingQueue.push(fileIndex); } try { if (beforeEach(files[fileIndex]) !== false) { if (fileIndex === files_count) { return; } var reader = new FileReader(), max_file_size = 1048576 * opts.maxfilesize; reader.index = fileIndex; if (files[fileIndex].size > max_file_size) { opts.error(errors[2], files[fileIndex], fileIndex); // Remove from queue processingQueue.forEach(function(value, key) { if (value === fileIndex) { processingQueue.splice(key, 1); } }); filesRejected++; return true; } reader.onerror = function(e) { switch(e.target.error.code) { case e.target.error.NOT_FOUND_ERR: opts.error(errors[4]); return false; case e.target.error.NOT_READABLE_ERR: opts.error(errors[5]); return false; case e.target.error.ABORT_ERR: opts.error(errors[6]); return false; default: opts.error(errors[7]); return false; }; }; reader.onloadend = !opts.beforeSend ? send : function (e) { opts.beforeSend(files[fileIndex], fileIndex, function () { send(e); }); }; reader.readAsDataURL(files[fileIndex]); } else { filesRejected++; } } catch (err) { // Remove from queue processingQueue.forEach(function(value, key) { if (value === fileIndex) { processingQueue.splice(key, 1); } }); opts.error(errors[0]); return false; } // If we still have work to do, if (workQueue.length > 0) { process(); } }; var send = function(e) { var fileIndex = (e.srcElement || e.target).index; // Sometimes the index is not attached to the // event object. Find it by size. Hack for sure. if (e.target.index === undefined) { e.target.index = getIndexBySize(e.total); } var xhr = new XMLHttpRequest(), upload = xhr.upload, file = files[e.target.index], index = e.target.index, start_time = new Date().getTime(), boundary = '------multipartformboundary' + (new Date()).getTime(), global_progress_index = global_progress.length, builder, newName = rename(file.name), mime = file.type; if (opts.withCredentials) { xhr.withCredentials = opts.withCredentials; } var data = atob(e.target.result.split(',')[1]); if (typeof newName === "string") { builder = getBuilder(newName, data, mime, boundary); } else { builder = getBuilder(file.name, data, mime, boundary); } upload.index = index; upload.file = file; upload.downloadStartTime = start_time; upload.currentStart = start_time; upload.currentProgress = 0; upload.global_progress_index = global_progress_index; upload.startData = 0; upload.addEventListener("progress", progress, false); // Allow url to be a method if (jQuery.isFunction(opts.url)) { xhr.open(opts.requestType, opts.url(), true); } else { xhr.open(opts.requestType, opts.url, true); } xhr.setRequestHeader('content-type', 'multipart/form-data; boundary=' + boundary); xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); // Add headers $.each(opts.headers, function(k, v) { xhr.setRequestHeader(k, v); }); xhr.sendAsBinary(builder); global_progress[global_progress_index] = 0; globalProgress(); opts.uploadStarted(index, file, files_count); xhr.onload = function() { var serverResponse = null; if (xhr.responseText) { try { serverResponse = jQuery.parseJSON(xhr.responseText); } catch (e) { serverResponse = xhr.responseText; } } var now = new Date().getTime(), timeDiff = now - start_time, result = opts.uploadFinished(index, file, serverResponse, timeDiff, xhr); filesDone++; // Remove from processing queue processingQueue.forEach(function(value, key) { if (value === fileIndex) { processingQueue.splice(key, 1); } }); // Add to donequeue doneQueue.push(fileIndex); // Make sure the global progress is updated global_progress[global_progress_index] = 100; globalProgress(); if (filesDone === (files_count - filesRejected)) { afterAll(); } if (result === false) { stop_loop = true; } // Pass any errors to the error option if (xhr.status < 200 || xhr.status > 299) { opts.error(xhr.statusText, file, fileIndex, xhr.status); } }; }; // Initiate the processing loop process(); } function getIndexBySize(size) { for (var i = 0; i < files_count; i++) { if (files[i].size === size) { return i; } } return undefined; } function rename(name) { return opts.rename(name); } function beforeEach(file) { return opts.beforeEach(file); } function afterAll() { return opts.afterAll(); } function dragEnter(e) { clearTimeout(doc_leave_timer); e.preventDefault(); opts.dragEnter.call(this, e); } function dragOver(e) { clearTimeout(doc_leave_timer); e.preventDefault(); opts.docOver.call(this, e); opts.dragOver.call(this, e); } function dragLeave(e) { clearTimeout(doc_leave_timer); opts.dragLeave.call(this, e); e.stopPropagation(); } function docDrop(e) { e.preventDefault(); opts.docLeave.call(this, e); return false; } function docEnter(e) { clearTimeout(doc_leave_timer); e.preventDefault(); opts.docEnter.call(this, e); return false; } function docOver(e) { clearTimeout(doc_leave_timer); e.preventDefault(); opts.docOver.call(this, e); return false; } function docLeave(e) { doc_leave_timer = setTimeout((function(_this) { return function() { opts.docLeave.call(_this, e); }; })(this), 200); } return this; }; function empty() {} try { if (XMLHttpRequest.prototype.sendAsBinary) { return; } XMLHttpRequest.prototype.sendAsBinary = function(datastr) { function byteValue(x) { return x.charCodeAt(0) & 0xff; } var ords = Array.prototype.map.call(datastr, byteValue); var ui8a = new Uint8Array(ords); // Not pretty: Chrome 22 deprecated sending ArrayBuffer, moving instead // to sending ArrayBufferView. Sadly, no proper way to detect this // functionality has been discovered. Happily, Chrome 22 also introduced // the base ArrayBufferView class, not present in Chrome 21. if ('ArrayBufferView' in window) this.send(ui8a); else this.send(ui8a.buffer); }; } catch (e) {} })(jQuery);