From e46b5e6bc2fdbba1450b72c4c908a3e085ade657 Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 4 Jan 2008 08:46:33 +0000 Subject: [PATCH] Port autosave to jquery. Props rmccue. see #3824 git-svn-id: http://svn.automattic.com/wordpress/trunk@6546 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/page-new.php | 2 - wp-admin/page.php | 6 +- wp-admin/post-new.php | 2 - wp-admin/post.php | 4 +- wp-includes/functions.php | 2 +- wp-includes/js/autosave.js | 159 +++-- wp-includes/js/jquery/jquery.schedule.js | 708 +++++++++++++++++++++++ wp-includes/post.php | 4 + wp-includes/script-loader.php | 3 +- 9 files changed, 791 insertions(+), 99 deletions(-) create mode 100644 wp-includes/js/jquery/jquery.schedule.js diff --git a/wp-admin/page-new.php b/wp-admin/page-new.php index daa06284b..e481e1680 100644 --- a/wp-admin/page-new.php +++ b/wp-admin/page-new.php @@ -3,8 +3,6 @@ require_once('admin.php'); $title = __('New Page'); $parent_file = 'post-new.php'; $editing = true; -wp_enqueue_script('prototype'); -wp_enqueue_script('jquery'); wp_enqueue_script('autosave'); require_once('admin-header.php'); ?> diff --git a/wp-admin/page.php b/wp-admin/page.php index 167c4110f..f71bf6306 100644 --- a/wp-admin/page.php +++ b/wp-admin/page.php @@ -52,11 +52,9 @@ case 'edit': exit(); } - if($post->post_status == 'draft') { - wp_enqueue_script('prototype'); - wp_enqueue_script('jquery'); + if ( 'draft' == $post->post_status ) wp_enqueue_script('autosave'); - } + require_once('admin-header.php'); if ( !current_user_can('edit_page', $page_ID) ) diff --git a/wp-admin/post-new.php b/wp-admin/post-new.php index e3a950727..6d75d4c25 100644 --- a/wp-admin/post-new.php +++ b/wp-admin/post-new.php @@ -3,8 +3,6 @@ require_once('admin.php'); $title = __('Create New Post'); $parent_file = 'post-new.php'; $editing = true; -wp_enqueue_script('prototype'); -wp_enqueue_script('jquery'); wp_enqueue_script('autosave'); wp_enqueue_script('post'); diff --git a/wp-admin/post.php b/wp-admin/post.php index d9d2e6673..f7c94b44f 100644 --- a/wp-admin/post.php +++ b/wp-admin/post.php @@ -60,10 +60,8 @@ case 'edit': wp_enqueue_script('post'); - if( 'draft' == $post->post_status ) { - wp_enqueue_script('prototype'); + if ( 'draft' == $post->post_status ) wp_enqueue_script('autosave'); - } require_once('admin-header.php'); diff --git a/wp-includes/functions.php b/wp-includes/functions.php index 997a9bff7..462ca1a70 100644 --- a/wp-includes/functions.php +++ b/wp-includes/functions.php @@ -968,7 +968,7 @@ function wp_nonce_url( $actionurl, $action = -1 ) { function wp_nonce_field( $action = -1, $name = "_wpnonce", $referer = true ) { $name = attribute_escape( $name ); - echo ''; + echo ''; if ( $referer ) wp_referer_field(); } diff --git a/wp-includes/js/autosave.js b/wp-includes/js/autosave.js index c8956ae4f..bdea35cca 100644 --- a/wp-includes/js/autosave.js +++ b/wp-includes/js/autosave.js @@ -2,20 +2,16 @@ var autosaveLast = ''; var autosavePeriodical; function autosave_start_timer() { - var form = $('post'); - autosaveLast = form.post_title.value+form.content.value; + autosaveLast = jQuery('#post #title').val()+jQuery('#post #content').val(); // Keep autosave_interval in sync with edit_post(). - autosavePeriodical = new PeriodicalExecuter(autosave, autosaveL10n.autosaveInterval); + autosavePeriodical = jQuery.schedule({time: autosaveL10n.autosaveInterval * 1000, func: autosave, repeat: true, protect: true}); + //Disable autosave after the form has been submitted - if(form.addEventListener) { - form.addEventListener("submit", function () { autosavePeriodical.currentlyExecuting = true; }, false); - } - if(form.attachEvent) { - form.save ? form.save.attachEvent("onclick", function () { autosavePeriodical.currentlyExecuting = true; }) : null; - form.submit ? form.submit.attachEvent("onclick", function () { autosavePeriodical.currentlyExecuting = true; }) : null; - form.publish ? form.publish.attachEvent("onclick", function () { autosavePeriodical.currentlyExecuting = true; }) : null; - form.deletepost ? form.deletepost.attachEvent("onclick", function () { autosavePeriodical.currentlyExecuting = true; }) : null; - } + jQuery("#post #submit").submit(function() { jQuery.cancel(autosavePeriodical); }); + jQuery("#post #save").click(function() { jQuery.cancel(autosavePeriodical); }); + jQuery("#post #submit").click(function() { jQuery.cancel(autosavePeriodical); }); + jQuery("#post #publish").click(function() { jQuery.cancel(autosavePeriodical); }); + jQuery("#post #deletepost").click(function() { jQuery.cancel(autosavePeriodical); }); } addLoadEvent(autosave_start_timer) @@ -26,13 +22,7 @@ function autosave_cur_time() { ((now.getSeconds() < 10) ? ":0" : ":") + now.getSeconds(); } -function autosave_update_nonce() { - var response = nonceAjax.response; - document.getElementsByName('_wpnonce')[0].value = response; -} - -function autosave_update_post_ID() { - var response = autosaveAjax.response; +function autosave_update_post_ID(response) { var res = parseInt(response); var message; @@ -40,31 +30,28 @@ function autosave_update_post_ID() { message = autosaveL10n.errorText.replace(/%response%/g, response); } else { message = autosaveL10n.saveText.replace(/%time%/g, autosave_cur_time()); - $('post_ID').name = "post_ID"; - $('post_ID').value = res; + jQuery('#post_ID').attr({name: "post_ID"}); + jQuery('#post_ID').val(res); // We need new nonces - nonceAjax = new sack(); - nonceAjax.element = null; - nonceAjax.setVar("action", "autosave-generate-nonces"); - nonceAjax.setVar("post_ID", res); - nonceAjax.setVar("cookie", document.cookie); - nonceAjax.setVar("post_type", $('post_type').value); - nonceAjax.requestFile = autosaveL10n.requestFile; - nonceAjax.onCompletion = autosave_update_nonce; - nonceAjax.method = "POST"; - nonceAjax.runAJAX(); - $('hiddenaction').value = 'editpost'; + jQuery.post(autosaveL10n.requestFile, { + action: "autosave-generate-nonces", + post_ID: res, + cookie: document.cookie, + post_type: jQuery('#post_type').val() + }, function(html) { + jQuery('#_wpnonce').val(html); + }); + jQuery('#hiddenaction').val('editpost'); } - $('autosave').innerHTML = message; + jQuery('#autosave').html(message); autosave_enable_buttons(); } function autosave_loading() { - $('autosave').innerHTML = autosaveL10n.savingText; + jQuery('#autosave').html(autosaveL10n.savingText); } -function autosave_saved() { - var response = autosaveAjax.response; +function autosave_saved(response) { var res = parseInt(response); var message; @@ -73,87 +60,87 @@ function autosave_saved() { } else { message = autosaveL10n.saveText.replace(/%time%/g, autosave_cur_time()); } - $('autosave').innerHTML = message; + jQuery('#autosave').html(message); autosave_enable_buttons(); } function autosave_disable_buttons() { - var form = $('post'); - form.save ? form.save.disabled = 'disabled' : null; - form.submit ? form.submit.disabled = 'disabled' : null; - form.publish ? form.publish.disabled = 'disabled' : null; - form.deletepost ? form.deletepost.disabled = 'disabled' : null; + jQuery("#post #save:enabled").attr('disabled', 'disabled'); + jQuery("#post #submit:enabled").attr('disabled', 'disabled'); + jQuery("#post #publish:enabled").attr('disabled', 'disabled'); + jQuery("#post #deletepost:enabled").attr('disabled', 'disabled'); setTimeout('autosave_enable_buttons();', 1000); // Re-enable 1 sec later. Just gives autosave a head start to avoid collisions. } function autosave_enable_buttons() { - var form = $('post'); - form.save ? form.save.disabled = '' : null; - form.submit ? form.submit.disabled = '' : null; - form.publish ? form.publish.disabled = '' : null; - form.deletepost ? form.deletepost.disabled = '' : null; + jQuery("#post #save:disabled").attr('disabled', ''); + jQuery("#post #submit:disabled").attr('disabled', ''); + jQuery("#post #publish:disabled").attr('disabled', ''); + jQuery("#post #deletepost:disabled").attr('disabled', ''); } function autosave() { - var form = $('post'); var rich = ((typeof tinyMCE != "undefined") && tinyMCE.getInstanceById('content')) ? true : false; - - autosaveAjax = new sack(); + var post_data = { + action: "autosave", + post_ID: jQuery("#post_ID").val() || 0, + post_title: jQuery("#title").val() || "", + cookie: document.cookie, + tags_input: jQuery("#tags-input").val() || "", + post_type: jQuery('#post_type').val() || "" + }; /* Gotta do this up here so we can check the length when tinyMCE is in use */ if ( typeof tinyMCE == "undefined" || tinyMCE.configs.length < 1 || rich == false ) { - autosaveAjax.setVar("content", form.content.value); + post_data["content"] = jQuery("#content").val(); } else { // Don't run while the TinyMCE spellcheck is on. if(tinyMCE.selectedInstance.spellcheckerOn) return; tinyMCE.wpTriggerSave(); - autosaveAjax.setVar("content", form.content.value); + post_data["content"] = jQuery("#content").val(); } - if(form.post_title.value.length==0 || form.content.value.length==0 || form.post_title.value+form.content.value == autosaveLast) + if(post_data["post_title"].length==0 || post_data["content"].length==0 || post_data["post_title"] + post_data["content"] == autosaveLast) { return; + } autosave_disable_buttons(); - autosaveLast = form.post_title.value+form.content.value; - - cats = document.getElementsByName("post_category[]"); + autosaveLast = jQuery("#title").val()+jQuery("#content").val(); goodcats = ([]); - for(i=0;i +** Licensed under GPL +** +** $LastChangedDate$ +** $LastChangedRevision$ +*/ + +/* + *
TEST BUTTON
+ *
+ * + * + */ + +(function($) { + + /* object constructor */ + $.scheduler = function () { + this.bucket = {}; + return; + }; + + /* object methods */ + $.scheduler.prototype = { + /* schedule a task */ + schedule: function () { + /* schedule context with default parameters */ + var ctx = { + "id": null, /* unique identifier of high-level schedule */ + "time": 1000, /* time in milliseconds after which the task is run */ + "repeat": false, /* whether schedule should be automatically repeated */ + "protect": false, /* whether schedule should be protected from double scheduling */ + "obj": null, /* function context object ("this") */ + "func": function(){}, /* function to call */ + "args": [] /* function arguments to pass */ + }; + + /* helper function: portable checking whether something is a function */ + function _isfn (fn) { + return ( + !!fn + && typeof fn != "string" + && typeof fn[0] == "undefined" + && RegExp("function", "i").test(fn + "") + ); + }; + + /* parse arguments into context parameters (part 1/4): + detect an override object (special case to support jQuery method) */ + var i = 0; + var override = false; + if (typeof arguments[i] == "object" && arguments.length > 1) { + override = true; + i++; + } + + /* parse arguments into context parameters (part 2/4): + support the flexible way of an associated array */ + if (typeof arguments[i] == "object") { + for (var option in arguments[i]) + if (typeof ctx[option] != "undefined") + ctx[option] = arguments[i][option]; + i++; + } + + /* parse arguments into context parameters (part 3/4): + support: schedule([time [, repeat], ]{{obj, methodname} | func}[, arg, ...]); */ + if ( typeof arguments[i] == "number" + || ( typeof arguments[i] == "string" + && arguments[i].match(RegExp("^[0-9]+[smhdw]$")))) + ctx["time"] = arguments[i++]; + if (typeof arguments[i] == "boolean") + ctx["repeat"] = arguments[i++]; + if (typeof arguments[i] == "boolean") + ctx["protect"] = arguments[i++]; + if ( typeof arguments[i] == "object" + && typeof arguments[i+1] == "string" + && _isfn(arguments[i][arguments[i+1]])) { + ctx["obj"] = arguments[i++]; + ctx["func"] = arguments[i++]; + } + else if ( typeof arguments[i] != "undefined" + && ( _isfn(arguments[i]) + || typeof arguments[i] == "string")) + ctx["func"] = arguments[i++]; + while (typeof arguments[i] != "undefined") + ctx["args"].push(arguments[i++]); + + /* parse arguments into context parameters (part 4/4): + apply parameters from override object */ + if (override) { + if (typeof arguments[1] == "object") { + for (var option in arguments[0]) + if ( typeof ctx[option] != "undefined" + && typeof arguments[1][option] == "undefined") + ctx[option] = arguments[0][option]; + } + else { + for (var option in arguments[0]) + if (typeof ctx[option] != "undefined") + ctx[option] = arguments[0][option]; + } + i++; + } + + /* annotate context with internals */ + ctx["_scheduler"] = this; /* internal: back-reference to scheduler object */ + ctx["_handle"] = null; /* internal: unique handle of low-level task */ + + /* determine time value in milliseconds */ + var match = String(ctx["time"]).match(RegExp("^([0-9]+)([smhdw])$")); + if (match && match[0] != "undefined" && match[1] != "undefined") + ctx["time"] = String(parseInt(match[1]) * + { s: 1000, m: 1000*60, h: 1000*60*60, + d: 1000*60*60*24, w: 1000*60*60*24*7 }[match[2]]); + + /* determine unique identifier of task */ + if (ctx["id"] == null) + ctx["id"] = ( String(ctx["repeat"]) + ":" + + String(ctx["protect"]) + ":" + + String(ctx["time"]) + ":" + + String(ctx["obj"]) + ":" + + String(ctx["func"]) + ":" + + String(ctx["args"]) ); + + /* optionally protect from duplicate calls */ + if (ctx["protect"]) + if (typeof this.bucket[ctx["id"]] != "undefined") + return this.bucket[ctx["id"]]; + + /* support execution of methods by name and arbitrary scripts */ + if (!_isfn(ctx["func"])) { + if ( ctx["obj"] != null + && typeof ctx["obj"] == "object" + && typeof ctx["func"] == "string" + && _isfn(ctx["obj"][ctx["func"]])) + /* method by name */ + ctx["func"] = ctx["obj"][ctx["func"]]; + else + /* arbitrary script */ + ctx["func"] = eval("function () { " + ctx["func"] + " }"); + } + + /* pass-through to internal scheduling operation */ + ctx["_handle"] = this._schedule(ctx); + + /* store context into bucket of scheduler object */ + this.bucket[ctx["id"]] = ctx; + + /* return context */ + return ctx; + }, + + /* re-schedule a task */ + reschedule: function (ctx) { + if (typeof ctx == "string") + ctx = this.bucket[ctx]; + + /* pass-through to internal scheduling operation */ + ctx["_handle"] = this._schedule(ctx); + + /* return context */ + return ctx; + }, + + /* internal scheduling operation */ + _schedule: function (ctx) { + /* closure to act as the call trampoline function */ + var trampoline = function () { + /* jump into function */ + var obj = (ctx["obj"] != null ? ctx["obj"] : ctx); + (ctx["func"]).apply(obj, ctx["args"]); + + /* either repeat scheduling and keep in bucket or + just stop scheduling and delete from scheduler bucket */ + if ( /* not cancelled from inside... */ + typeof (ctx["_scheduler"]).bucket[ctx["id"]] != "undefined" + && /* ...and repeating requested */ + ctx["repeat"]) + (ctx["_scheduler"])._schedule(ctx); + else + delete (ctx["_scheduler"]).bucket[ctx["id"]]; + }; + + /* schedule task and return handle */ + return setTimeout(trampoline, ctx["time"]); + }, + + /* cancel a scheduled task */ + cancel: function (ctx) { + if (typeof ctx == "string") + ctx = this.bucket[ctx]; + + /* cancel scheduled task */ + if (typeof ctx == "object") { + clearTimeout(ctx["_handle"]); + delete this.bucket[ctx["id"]]; + } + } + }; + + /* integrate a global instance of the scheduler into the global jQuery object */ + $.extend({ + scheduler$: new $.scheduler(), + schedule: function () { return $.scheduler$.schedule.apply ($.scheduler$, arguments) }, + reschedule: function () { return $.scheduler$.reschedule.apply($.scheduler$, arguments) }, + cancel: function () { return $.scheduler$.cancel.apply ($.scheduler$, arguments) } + }); + + /* integrate scheduling convinience method into all jQuery objects */ + $.fn.extend({ + schedule: function () { + var a = [ {} ]; + for (var i = 0; i < arguments.length; i++) + a.push(arguments[i]); + return this.each(function () { + a[0] = { "id": this, "obj": this }; + return $.schedule.apply($, a); + }); + } + }); + +})(jQuery); + +/* +** jquery.schedule.js -- jQuery plugin for scheduled/deferred actions +** Copyright (c) 2007 Ralf S. Engelschall +** Licensed under GPL +** +** $LastChangedDate$ +** $LastChangedRevision$ +*/ + +/* + *
TEST BUTTON
+ *
+ * + * + */ + +(function($) { + + /* object constructor */ + $.scheduler = function () { + this.bucket = {}; + return; + }; + + /* object methods */ + $.scheduler.prototype = { + /* schedule a task */ + schedule: function () { + /* schedule context with default parameters */ + var ctx = { + "id": null, /* unique identifier of high-level schedule */ + "time": 1000, /* time in milliseconds after which the task is run */ + "repeat": false, /* whether schedule should be automatically repeated */ + "protect": false, /* whether schedule should be protected from double scheduling */ + "obj": null, /* function context object ("this") */ + "func": function(){}, /* function to call */ + "args": [] /* function arguments to pass */ + }; + + /* helper function: portable checking whether something is a function */ + function _isfn (fn) { + return ( + !!fn + && typeof fn != "string" + && typeof fn[0] == "undefined" + && RegExp("function", "i").test(fn + "") + ); + }; + + /* parse arguments into context parameters (part 1/4): + detect an override object (special case to support jQuery method) */ + var i = 0; + var override = false; + if (typeof arguments[i] == "object" && arguments.length > 1) { + override = true; + i++; + } + + /* parse arguments into context parameters (part 2/4): + support the flexible way of an associated array */ + if (typeof arguments[i] == "object") { + for (var option in arguments[i]) + if (typeof ctx[option] != "undefined") + ctx[option] = arguments[i][option]; + i++; + } + + /* parse arguments into context parameters (part 3/4): + support: schedule([time [, repeat], ]{{obj, methodname} | func}[, arg, ...]); */ + if ( typeof arguments[i] == "number" + || ( typeof arguments[i] == "string" + && arguments[i].match(RegExp("^[0-9]+[smhdw]$")))) + ctx["time"] = arguments[i++]; + if (typeof arguments[i] == "boolean") + ctx["repeat"] = arguments[i++]; + if (typeof arguments[i] == "boolean") + ctx["protect"] = arguments[i++]; + if ( typeof arguments[i] == "object" + && typeof arguments[i+1] == "string" + && _isfn(arguments[i][arguments[i+1]])) { + ctx["obj"] = arguments[i++]; + ctx["func"] = arguments[i++]; + } + else if ( typeof arguments[i] != "undefined" + && ( _isfn(arguments[i]) + || typeof arguments[i] == "string")) + ctx["func"] = arguments[i++]; + while (typeof arguments[i] != "undefined") + ctx["args"].push(arguments[i++]); + + /* parse arguments into context parameters (part 4/4): + apply parameters from override object */ + if (override) { + if (typeof arguments[1] == "object") { + for (var option in arguments[0]) + if ( typeof ctx[option] != "undefined" + && typeof arguments[1][option] == "undefined") + ctx[option] = arguments[0][option]; + } + else { + for (var option in arguments[0]) + if (typeof ctx[option] != "undefined") + ctx[option] = arguments[0][option]; + } + i++; + } + + /* annotate context with internals */ + ctx["_scheduler"] = this; /* internal: back-reference to scheduler object */ + ctx["_handle"] = null; /* internal: unique handle of low-level task */ + + /* determine time value in milliseconds */ + var match = String(ctx["time"]).match(RegExp("^([0-9]+)([smhdw])$")); + if (match && match[0] != "undefined" && match[1] != "undefined") + ctx["time"] = String(parseInt(match[1]) * + { s: 1000, m: 1000*60, h: 1000*60*60, + d: 1000*60*60*24, w: 1000*60*60*24*7 }[match[2]]); + + /* determine unique identifier of task */ + if (ctx["id"] == null) + ctx["id"] = ( String(ctx["repeat"]) + ":" + + String(ctx["protect"]) + ":" + + String(ctx["time"]) + ":" + + String(ctx["obj"]) + ":" + + String(ctx["func"]) + ":" + + String(ctx["args"]) ); + + /* optionally protect from duplicate calls */ + if (ctx["protect"]) + if (typeof this.bucket[ctx["id"]] != "undefined") + return this.bucket[ctx["id"]]; + + /* support execution of methods by name and arbitrary scripts */ + if (!_isfn(ctx["func"])) { + if ( ctx["obj"] != null + && typeof ctx["obj"] == "object" + && typeof ctx["func"] == "string" + && _isfn(ctx["obj"][ctx["func"]])) + /* method by name */ + ctx["func"] = ctx["obj"][ctx["func"]]; + else + /* arbitrary script */ + ctx["func"] = eval("function () { " + ctx["func"] + " }"); + } + + /* pass-through to internal scheduling operation */ + ctx["_handle"] = this._schedule(ctx); + + /* store context into bucket of scheduler object */ + this.bucket[ctx["id"]] = ctx; + + /* return context */ + return ctx; + }, + + /* re-schedule a task */ + reschedule: function (ctx) { + if (typeof ctx == "string") + ctx = this.bucket[ctx]; + + /* pass-through to internal scheduling operation */ + ctx["_handle"] = this._schedule(ctx); + + /* return context */ + return ctx; + }, + + /* internal scheduling operation */ + _schedule: function (ctx) { + /* closure to act as the call trampoline function */ + var trampoline = function () { + /* jump into function */ + var obj = (ctx["obj"] != null ? ctx["obj"] : ctx); + (ctx["func"]).apply(obj, ctx["args"]); + + /* either repeat scheduling and keep in bucket or + just stop scheduling and delete from scheduler bucket */ + if ( /* not cancelled from inside... */ + typeof (ctx["_scheduler"]).bucket[ctx["id"]] != "undefined" + && /* ...and repeating requested */ + ctx["repeat"]) + (ctx["_scheduler"])._schedule(ctx); + else + delete (ctx["_scheduler"]).bucket[ctx["id"]]; + }; + + /* schedule task and return handle */ + return setTimeout(trampoline, ctx["time"]); + }, + + /* cancel a scheduled task */ + cancel: function (ctx) { + if (typeof ctx == "string") + ctx = this.bucket[ctx]; + + /* cancel scheduled task */ + if (typeof ctx == "object") { + clearTimeout(ctx["_handle"]); + delete this.bucket[ctx["id"]]; + } + } + }; + + /* integrate a global instance of the scheduler into the global jQuery object */ + $.extend({ + scheduler$: new $.scheduler(), + schedule: function () { return $.scheduler$.schedule.apply ($.scheduler$, arguments) }, + reschedule: function () { return $.scheduler$.reschedule.apply($.scheduler$, arguments) }, + cancel: function () { return $.scheduler$.cancel.apply ($.scheduler$, arguments) } + }); + + /* integrate scheduling convinience method into all jQuery objects */ + $.fn.extend({ + schedule: function () { + var a = [ {} ]; + for (var i = 0; i < arguments.length; i++) + a.push(arguments[i]); + return this.each(function () { + a[0] = { "id": this, "obj": this }; + return $.schedule.apply($, a); + }); + } + }); + +})(jQuery); + +/* +** jquery.schedule.js -- jQuery plugin for scheduled/deferred actions +** Copyright (c) 2007 Ralf S. Engelschall +** Licensed under GPL +** +** $LastChangedDate$ +** $LastChangedRevision$ +*/ + +/* + *
TEST BUTTON
+ *
+ * + * + */ + +(function($) { + + /* object constructor */ + $.scheduler = function () { + this.bucket = {}; + return; + }; + + /* object methods */ + $.scheduler.prototype = { + /* schedule a task */ + schedule: function () { + /* schedule context with default parameters */ + var ctx = { + "id": null, /* unique identifier of high-level schedule */ + "time": 1000, /* time in milliseconds after which the task is run */ + "repeat": false, /* whether schedule should be automatically repeated */ + "protect": false, /* whether schedule should be protected from double scheduling */ + "obj": null, /* function context object ("this") */ + "func": function(){}, /* function to call */ + "args": [] /* function arguments to pass */ + }; + + /* helper function: portable checking whether something is a function */ + function _isfn (fn) { + return ( + !!fn + && typeof fn != "string" + && typeof fn[0] == "undefined" + && RegExp("function", "i").test(fn + "") + ); + }; + + /* parse arguments into context parameters (part 1/4): + detect an override object (special case to support jQuery method) */ + var i = 0; + var override = false; + if (typeof arguments[i] == "object" && arguments.length > 1) { + override = true; + i++; + } + + /* parse arguments into context parameters (part 2/4): + support the flexible way of an associated array */ + if (typeof arguments[i] == "object") { + for (var option in arguments[i]) + if (typeof ctx[option] != "undefined") + ctx[option] = arguments[i][option]; + i++; + } + + /* parse arguments into context parameters (part 3/4): + support: schedule([time [, repeat], ]{{obj, methodname} | func}[, arg, ...]); */ + if ( typeof arguments[i] == "number" + || ( typeof arguments[i] == "string" + && arguments[i].match(RegExp("^[0-9]+[smhdw]$")))) + ctx["time"] = arguments[i++]; + if (typeof arguments[i] == "boolean") + ctx["repeat"] = arguments[i++]; + if (typeof arguments[i] == "boolean") + ctx["protect"] = arguments[i++]; + if ( typeof arguments[i] == "object" + && typeof arguments[i+1] == "string" + && _isfn(arguments[i][arguments[i+1]])) { + ctx["obj"] = arguments[i++]; + ctx["func"] = arguments[i++]; + } + else if ( typeof arguments[i] != "undefined" + && ( _isfn(arguments[i]) + || typeof arguments[i] == "string")) + ctx["func"] = arguments[i++]; + while (typeof arguments[i] != "undefined") + ctx["args"].push(arguments[i++]); + + /* parse arguments into context parameters (part 4/4): + apply parameters from override object */ + if (override) { + if (typeof arguments[1] == "object") { + for (var option in arguments[0]) + if ( typeof ctx[option] != "undefined" + && typeof arguments[1][option] == "undefined") + ctx[option] = arguments[0][option]; + } + else { + for (var option in arguments[0]) + if (typeof ctx[option] != "undefined") + ctx[option] = arguments[0][option]; + } + i++; + } + + /* annotate context with internals */ + ctx["_scheduler"] = this; /* internal: back-reference to scheduler object */ + ctx["_handle"] = null; /* internal: unique handle of low-level task */ + + /* determine time value in milliseconds */ + var match = String(ctx["time"]).match(RegExp("^([0-9]+)([smhdw])$")); + if (match && match[0] != "undefined" && match[1] != "undefined") + ctx["time"] = String(parseInt(match[1]) * + { s: 1000, m: 1000*60, h: 1000*60*60, + d: 1000*60*60*24, w: 1000*60*60*24*7 }[match[2]]); + + /* determine unique identifier of task */ + if (ctx["id"] == null) + ctx["id"] = ( String(ctx["repeat"]) + ":" + + String(ctx["protect"]) + ":" + + String(ctx["time"]) + ":" + + String(ctx["obj"]) + ":" + + String(ctx["func"]) + ":" + + String(ctx["args"]) ); + + /* optionally protect from duplicate calls */ + if (ctx["protect"]) + if (typeof this.bucket[ctx["id"]] != "undefined") + return this.bucket[ctx["id"]]; + + /* support execution of methods by name and arbitrary scripts */ + if (!_isfn(ctx["func"])) { + if ( ctx["obj"] != null + && typeof ctx["obj"] == "object" + && typeof ctx["func"] == "string" + && _isfn(ctx["obj"][ctx["func"]])) + /* method by name */ + ctx["func"] = ctx["obj"][ctx["func"]]; + else + /* arbitrary script */ + ctx["func"] = eval("function () { " + ctx["func"] + " }"); + } + + /* pass-through to internal scheduling operation */ + ctx["_handle"] = this._schedule(ctx); + + /* store context into bucket of scheduler object */ + this.bucket[ctx["id"]] = ctx; + + /* return context */ + return ctx; + }, + + /* re-schedule a task */ + reschedule: function (ctx) { + if (typeof ctx == "string") + ctx = this.bucket[ctx]; + + /* pass-through to internal scheduling operation */ + ctx["_handle"] = this._schedule(ctx); + + /* return context */ + return ctx; + }, + + /* internal scheduling operation */ + _schedule: function (ctx) { + /* closure to act as the call trampoline function */ + var trampoline = function () { + /* jump into function */ + var obj = (ctx["obj"] != null ? ctx["obj"] : ctx); + (ctx["func"]).apply(obj, ctx["args"]); + + /* either repeat scheduling and keep in bucket or + just stop scheduling and delete from scheduler bucket */ + if ( /* not cancelled from inside... */ + typeof (ctx["_scheduler"]).bucket[ctx["id"]] != "undefined" + && /* ...and repeating requested */ + ctx["repeat"]) + (ctx["_scheduler"])._schedule(ctx); + else + delete (ctx["_scheduler"]).bucket[ctx["id"]]; + }; + + /* schedule task and return handle */ + return setTimeout(trampoline, ctx["time"]); + }, + + /* cancel a scheduled task */ + cancel: function (ctx) { + if (typeof ctx == "string") + ctx = this.bucket[ctx]; + + /* cancel scheduled task */ + if (typeof ctx == "object") { + clearTimeout(ctx["_handle"]); + delete this.bucket[ctx["id"]]; + } + } + }; + + /* integrate a global instance of the scheduler into the global jQuery object */ + $.extend({ + scheduler$: new $.scheduler(), + schedule: function () { return $.scheduler$.schedule.apply ($.scheduler$, arguments) }, + reschedule: function () { return $.scheduler$.reschedule.apply($.scheduler$, arguments) }, + cancel: function () { return $.scheduler$.cancel.apply ($.scheduler$, arguments) } + }); + + /* integrate scheduling convinience method into all jQuery objects */ + $.fn.extend({ + schedule: function () { + var a = [ {} ]; + for (var i = 0; i < arguments.length; i++) + a.push(arguments[i]); + return this.each(function () { + a[0] = { "id": this, "obj": this }; + return $.schedule.apply($, a); + }); + } + }); + +})(jQuery); + diff --git a/wp-includes/post.php b/wp-includes/post.php index 82f114a94..4c0f80b95 100644 --- a/wp-includes/post.php +++ b/wp-includes/post.php @@ -1002,11 +1002,15 @@ function wp_insert_post($postarr = array()) { if (empty($post_date)) { if ( !in_array($post_status, array('draft', 'pending')) ) $post_date = current_time('mysql'); + else + $post_date = '0000-00-00 00:00:00'; } if (empty($post_date_gmt)) { if ( !in_array($post_status, array('draft', 'pending')) ) $post_date_gmt = get_gmt_from_date($post_date); + else + $post_date_gmt = '0000-00-00 00:00:00'; } if ( $update ) { diff --git a/wp-includes/script-loader.php b/wp-includes/script-loader.php index 696b55222..9e18fb591 100644 --- a/wp-includes/script-loader.php +++ b/wp-includes/script-loader.php @@ -36,7 +36,7 @@ class WP_Scripts { $this->add( 'prototype', '/wp-includes/js/prototype.js', false, '1.6'); - $this->add( 'autosave', '/wp-includes/js/autosave.js', array('prototype', 'sack'), '20070306'); + $this->add( 'autosave', '/wp-includes/js/autosave.js', array('jquery', 'schedule'), '20080104'); $this->localize( 'autosave', 'autosaveL10n', array( 'autosaveInterval' => apply_filters('autosave_interval', '120'), 'errorText' => __('Error: %response%'), @@ -80,6 +80,7 @@ class WP_Scripts { $this->add( 'interface', '/wp-includes/js/jquery/interface.js', array('jquery'), '1.2'); $this->add( 'dimensions', '/wp-includes/js/jquery/jquery.dimensions.min.js', array('jquery'), '1.1.2'); $this->add( 'suggest', '/wp-includes/js/jquery/suggest.js', array('dimensions'), '1.1'); + $this->add( 'schedule', '/wp-includes/js/jquery/jquery.schedule.js', array('jquery'), '20'); if ( is_admin() ) { global $pagenow;