git-svn-id: https://plugins.svn.wordpress.org/pagemash/trunk@32360 b8457f37-d9ea-0310-8a92-e5e31aec5664

This commit is contained in:
jmash 2008-02-20 14:40:54 +00:00
parent 7004fcef1d
commit 1cd3cb4698
9 changed files with 8448 additions and 158 deletions

View File

@ -13,6 +13,17 @@ Customise the order your pages are listed in with a simple Ajax drag-and-drop ad
If you want to see an example of the admin page check out: http://joelstarnes.co.uk/pagemash/example
= Development Version 1.0.0 beta =
I have just finished a major rebuild of the plugin to give full recursive suppot for unlimited nested children in a collapsable list which I've decided to release as the first major version 1.0.0. but it'd be really helpful if some people can download the 1.0.0 beta and give me some feedback to iron out any bugs.
http://joelstarnes.co.uk/pagemash/example_v1.0.0
http://wordpress.org/extend/plugins/pagemash/download/pagemash.1.0.0.zip
== Installation ==
1. Download Plugin
@ -20,42 +31,25 @@ If you want to see an example of the admin page check out: http://joelstarnes.co
1. Activate in 'Plugins' admin menu
1. {Edit your Template}
In most cases the plugin should work straight out the box, since most templates will include something similar to: `wp_list_pages('title_li=<h2>Pages</h2>);`
In most cases the plugin should work straight out the box so give it an install and if then there is further info available in the plugin's admin page under 'Show further info'.
However to achieve full functionality including the 'exclude pages' feature you should replace the wp_list_pages() function with the following php code:
`if(function_exists('pageMash_exclude_pages'))`
`{$exclude_pages=pageMash_exclude_pages();} else{$exclude_pages='';}`
`wp_list_pages('title_li=<h2>Pages</h2>&exclude='.$exclude_pages);`
You can place the code wherever you would like your page listings to appear;
usually either the header.php or sidebar.php file found in: `wp-content\themes\theme_name`
== Frequently Asked Questions ==
If you have any questions or comments,
please drop me an email: joel@joelstarnes.co.uk
= Can I use this with the 'Pages' sidebar widget? =
Yes. Go into the wordpress admin; Presentation > Widgets and drag the pages widget to the sidebar, then go to it's settings by clicking the icon on the right and ensure that 'sort by' value is set to 'page order'.
Note however that the exclude pages feature will not work, so disable this in the top of the pagemash.php file by setting '$excludePagesFeature = false;'.
== Screenshots ==
1. Admin Interface.
2. If you are having problems using the pages widget; goto [Admin > Presentation > Widgets] and check that the 'sort by' value is set to 'page order'.
== Localization ==
Currently only available in english.
== Limitations==
The plugin will currently only handle top level pages.
==Change Log==
@ -65,9 +59,10 @@ The plugin will currently only handle top level pages.
0.1.2 > Fixed CSS&JS headers to only display on pageMash admin
0.1.3 > Fixed exclude pages feature
0.1.3 > Fixed exclude pages feature \n
1.0.0 beta > Major rebuild > Recusive page handles unlimited nested children, collapsable list items, interface makeover...
==Road Map==
== Localization ==
For the next majour release I hope to support children pages and allow these to be sorted and moved between different parents in a nested list fashion.
Currently only available in english.

BIN
collapse.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 740 B

BIN
expand.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 B

806
myjson.php Normal file
View File

@ -0,0 +1,806 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Converts to and from JSON format.
*
* JSON (JavaScript Object Notation) is a lightweight data-interchange
* format. It is easy for humans to read and write. It is easy for machines
* to parse and generate. It is based on a subset of the JavaScript
* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
* This feature can also be found in Python. JSON is a text format that is
* completely language independent but uses conventions that are familiar
* to programmers of the C-family of languages, including C, C++, C#, Java,
* JavaScript, Perl, TCL, and many others. These properties make JSON an
* ideal data-interchange language.
*
* This package provides a simple encoder and decoder for JSON notation. It
* is intended for use with client-side Javascript applications that make
* use of HTTPRequest to perform server communication functions - data can
* be encoded into JSON notation for use in a client-side javascript, or
* decoded from incoming Javascript requests. JSON format is native to
* Javascript, and can be directly eval()'ed with no further parsing
* overhead
*
* All strings should be in ASCII or UTF-8 format!
*
* LICENSE: Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met: Redistributions of source code must retain the
* above copyright notice, this list of conditions and the following
* disclaimer. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* @category
* @package Services_JSON
* @author Michal Migurski <mike-json@teczno.com>
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
* @copyright 2005 Michal Migurski
* @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
* @license http://www.opensource.org/licenses/bsd-license.php
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
*/
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_SLICE', 1);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_STR', 2);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_ARR', 3);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_OBJ', 4);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_CMT', 5);
/**
* Behavior switch for Services_JSON::decode()
*/
define('SERVICES_JSON_LOOSE_TYPE', 16);
/**
* Behavior switch for Services_JSON::decode()
*/
define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
/**
* Converts to and from JSON format.
*
* Brief example of use:
*
* <code>
* // create a new instance of Services_JSON
* $json = new Services_JSON();
*
* // convert a complexe value to JSON notation, and send it to the browser
* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
* $output = $json->encode($value);
*
* print($output);
* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
*
* // accept incoming POST data, assumed to be in JSON notation
* $input = file_get_contents('php://input', 1000000);
* $value = $json->decode($input);
* </code>
*/
class Services_JSON
{
/**
* constructs a new JSON instance
*
* @param int $use object behavior flags; combine with boolean-OR
*
* possible values:
* - SERVICES_JSON_LOOSE_TYPE: loose typing.
* "{...}" syntax creates associative arrays
* instead of objects in decode().
* - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
* Values which can't be encoded (e.g. resources)
* appear as NULL instead of throwing errors.
* By default, a deeply-nested resource will
* bubble up with an error, so all return values
* from encode() should be checked with isError()
*/
function Services_JSON($use = 0)
{
$this->use = $use;
}
/**
* convert a string from one UTF-16 char to one UTF-8 char
*
* Normally should be handled by mb_convert_encoding, but
* provides a slower PHP-only method for installations
* that lack the multibye string extension.
*
* @param string $utf16 UTF-16 character
* @return string UTF-8 character
* @access private
*/
function utf162utf8($utf16)
{
// oh please oh please oh please oh please oh please
if(function_exists('mb_convert_encoding')) {
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
}
$bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
switch(true) {
case ((0x7F & $bytes) == $bytes):
// this case should never be reached, because we are in ASCII range
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0x7F & $bytes);
case (0x07FF & $bytes) == $bytes:
// return a 2-byte UTF-8 character
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0xC0 | (($bytes >> 6) & 0x1F))
. chr(0x80 | ($bytes & 0x3F));
case (0xFFFF & $bytes) == $bytes:
// return a 3-byte UTF-8 character
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0xE0 | (($bytes >> 12) & 0x0F))
. chr(0x80 | (($bytes >> 6) & 0x3F))
. chr(0x80 | ($bytes & 0x3F));
}
// ignoring UTF-32 for now, sorry
return '';
}
/**
* convert a string from one UTF-8 char to one UTF-16 char
*
* Normally should be handled by mb_convert_encoding, but
* provides a slower PHP-only method for installations
* that lack the multibye string extension.
*
* @param string $utf8 UTF-8 character
* @return string UTF-16 character
* @access private
*/
function utf82utf16($utf8)
{
// oh please oh please oh please oh please oh please
if(function_exists('mb_convert_encoding')) {
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
}
switch(strlen($utf8)) {
case 1:
// this case should never be reached, because we are in ASCII range
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return $utf8;
case 2:
// return a UTF-16 character from a 2-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0x07 & (ord($utf8{0}) >> 2))
. chr((0xC0 & (ord($utf8{0}) << 6))
| (0x3F & ord($utf8{1})));
case 3:
// return a UTF-16 character from a 3-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr((0xF0 & (ord($utf8{0}) << 4))
| (0x0F & (ord($utf8{1}) >> 2)))
. chr((0xC0 & (ord($utf8{1}) << 6))
| (0x7F & ord($utf8{2})));
}
// ignoring UTF-32 for now, sorry
return '';
}
/**
* encodes an arbitrary variable into JSON format
*
* @param mixed $var any number, boolean, string, array, or object to be encoded.
* see argument 1 to Services_JSON() above for array-parsing behavior.
* if var is a strng, note that encode() always expects it
* to be in ASCII or UTF-8 format!
*
* @return mixed JSON string representation of input var or an error if a problem occurs
* @access public
*/
function encode($var)
{
switch (gettype($var)) {
case 'boolean':
return $var ? 'true' : 'false';
case 'NULL':
return 'null';
case 'integer':
return (int) $var;
case 'double':
case 'float':
return (float) $var;
case 'string':
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
$ascii = '';
$strlen_var = strlen($var);
/*
* Iterate over every character in the string,
* escaping with a slash or encoding to UTF-8 where necessary
*/
for ($c = 0; $c < $strlen_var; ++$c) {
$ord_var_c = ord($var{$c});
switch (true) {
case $ord_var_c == 0x08:
$ascii .= '\b';
break;
case $ord_var_c == 0x09:
$ascii .= '\t';
break;
case $ord_var_c == 0x0A:
$ascii .= '\n';
break;
case $ord_var_c == 0x0C:
$ascii .= '\f';
break;
case $ord_var_c == 0x0D:
$ascii .= '\r';
break;
case $ord_var_c == 0x22:
case $ord_var_c == 0x2F:
case $ord_var_c == 0x5C:
// double quote, slash, slosh
$ascii .= '\\'.$var{$c};
break;
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
// characters U-00000000 - U-0000007F (same as ASCII)
$ascii .= $var{$c};
break;
case (($ord_var_c & 0xE0) == 0xC0):
// characters U-00000080 - U-000007FF, mask 110XXXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c, ord($var{$c + 1}));
$c += 1;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xF0) == 0xE0):
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}));
$c += 2;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xF8) == 0xF0):
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}));
$c += 3;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xFC) == 0xF8):
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}),
ord($var{$c + 4}));
$c += 4;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
case (($ord_var_c & 0xFE) == 0xFC):
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}),
ord($var{$c + 4}),
ord($var{$c + 5}));
$c += 5;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
break;
}
}
return '"'.$ascii.'"';
case 'array':
/*
* As per JSON spec if any array key is not an integer
* we must treat the the whole array as an object. We
* also try to catch a sparsely populated associative
* array with numeric keys here because some JS engines
* will create an array with empty indexes up to
* max_index which can cause memory issues and because
* the keys, which may be relevant, will be remapped
* otherwise.
*
* As per the ECMA and JSON specification an object may
* have any string as a property. Unfortunately due to
* a hole in the ECMA specification if the key is a
* ECMA reserved word or starts with a digit the
* parameter is only accessible using ECMAScript's
* bracket notation.
*/
// treat as a JSON object
if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
$properties = array_map(array($this, 'name_value'),
array_keys($var),
array_values($var));
foreach($properties as $property) {
if(Services_JSON::isError($property)) {
return $property;
}
}
return '{' . join(',', $properties) . '}';
}
// treat it like a regular array
$elements = array_map(array($this, 'encode'), $var);
foreach($elements as $element) {
if(Services_JSON::isError($element)) {
return $element;
}
}
return '[' . join(',', $elements) . ']';
case 'object':
$vars = get_object_vars($var);
$properties = array_map(array($this, 'name_value'),
array_keys($vars),
array_values($vars));
foreach($properties as $property) {
if(Services_JSON::isError($property)) {
return $property;
}
}
return '{' . join(',', $properties) . '}';
default:
return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
? 'null'
: new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
}
}
/**
* array-walking function for use in generating JSON-formatted name-value pairs
*
* @param string $name name of key to use
* @param mixed $value reference to an array element to be encoded
*
* @return string JSON-formatted name-value pair, like '"name":value'
* @access private
*/
function name_value($name, $value)
{
$encoded_value = $this->encode($value);
if(Services_JSON::isError($encoded_value)) {
return $encoded_value;
}
return $this->encode(strval($name)) . ':' . $encoded_value;
}
/**
* reduce a string by removing leading and trailing comments and whitespace
*
* @param $str string string value to strip of comments and whitespace
*
* @return string string value stripped of comments and whitespace
* @access private
*/
function reduce_string($str)
{
$str = preg_replace(array(
// eliminate single line comments in '// ...' form
'#^\s*//(.+)$#m',
// eliminate multi-line comments in '/* ... */' form, at start of string
'#^\s*/\*(.+)\*/#Us',
// eliminate multi-line comments in '/* ... */' form, at end of string
'#/\*(.+)\*/\s*$#Us'
), '', $str);
// eliminate extraneous space
return trim($str);
}
/**
* decodes a JSON string into appropriate variable
*
* @param string $str JSON-formatted string
*
* @return mixed number, boolean, string, array, or object
* corresponding to given JSON input string.
* See argument 1 to Services_JSON() above for object-output behavior.
* Note that decode() always returns strings
* in ASCII or UTF-8 format!
* @access public
*/
function decode($str)
{
$str = $this->reduce_string($str);
switch (strtolower($str)) {
case 'true':
return true;
case 'false':
return false;
case 'null':
return null;
default:
$m = array();
if (is_numeric($str)) {
// Lookie-loo, it's a number
// This would work on its own, but I'm trying to be
// good about returning integers where appropriate:
// return (float)$str;
// Return float or int, as appropriate
return ((float)$str == (integer)$str)
? (integer)$str
: (float)$str;
} elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
// STRINGS RETURNED IN UTF-8 FORMAT
$delim = substr($str, 0, 1);
$chrs = substr($str, 1, -1);
$utf8 = '';
$strlen_chrs = strlen($chrs);
for ($c = 0; $c < $strlen_chrs; ++$c) {
$substr_chrs_c_2 = substr($chrs, $c, 2);
$ord_chrs_c = ord($chrs{$c});
switch (true) {
case $substr_chrs_c_2 == '\b':
$utf8 .= chr(0x08);
++$c;
break;
case $substr_chrs_c_2 == '\t':
$utf8 .= chr(0x09);
++$c;
break;
case $substr_chrs_c_2 == '\n':
$utf8 .= chr(0x0A);
++$c;
break;
case $substr_chrs_c_2 == '\f':
$utf8 .= chr(0x0C);
++$c;
break;
case $substr_chrs_c_2 == '\r':
$utf8 .= chr(0x0D);
++$c;
break;
case $substr_chrs_c_2 == '\\"':
case $substr_chrs_c_2 == '\\\'':
case $substr_chrs_c_2 == '\\\\':
case $substr_chrs_c_2 == '\\/':
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
$utf8 .= $chrs{++$c};
}
break;
case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
// single, escaped unicode character
$utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
. chr(hexdec(substr($chrs, ($c + 4), 2)));
$utf8 .= $this->utf162utf8($utf16);
$c += 5;
break;
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
$utf8 .= $chrs{$c};
break;
case ($ord_chrs_c & 0xE0) == 0xC0:
// characters U-00000080 - U-000007FF, mask 110XXXXX
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 2);
++$c;
break;
case ($ord_chrs_c & 0xF0) == 0xE0:
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 3);
$c += 2;
break;
case ($ord_chrs_c & 0xF8) == 0xF0:
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 4);
$c += 3;
break;
case ($ord_chrs_c & 0xFC) == 0xF8:
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 5);
$c += 4;
break;
case ($ord_chrs_c & 0xFE) == 0xFC:
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$utf8 .= substr($chrs, $c, 6);
$c += 5;
break;
}
}
return $utf8;
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
// array, or object notation
if ($str{0} == '[') {
$stk = array(SERVICES_JSON_IN_ARR);
$arr = array();
} else {
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$stk = array(SERVICES_JSON_IN_OBJ);
$obj = array();
} else {
$stk = array(SERVICES_JSON_IN_OBJ);
$obj = new stdClass();
}
}
array_push($stk, array('what' => SERVICES_JSON_SLICE,
'where' => 0,
'delim' => false));
$chrs = substr($str, 1, -1);
$chrs = $this->reduce_string($chrs);
if ($chrs == '') {
if (reset($stk) == SERVICES_JSON_IN_ARR) {
return $arr;
} else {
return $obj;
}
}
//print("\nparsing {$chrs}\n");
$strlen_chrs = strlen($chrs);
for ($c = 0; $c <= $strlen_chrs; ++$c) {
$top = end($stk);
$substr_chrs_c_2 = substr($chrs, $c, 2);
if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
// found a comma that is not inside a string, array, etc.,
// OR we've reached the end of the character list
$slice = substr($chrs, $top['where'], ($c - $top['where']));
array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
if (reset($stk) == SERVICES_JSON_IN_ARR) {
// we are in an array, so just push an element onto the stack
array_push($arr, $this->decode($slice));
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
// we are in an object, so figure
// out the property name and set an
// element in an associative array,
// for now
$parts = array();
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
// "name":value pair
$key = $this->decode($parts[1]);
$val = $this->decode($parts[2]);
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
// name:value pair, where name is unquoted
$key = $parts[1];
$val = $this->decode($parts[2]);
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
$obj[$key] = $val;
} else {
$obj->$key = $val;
}
}
}
} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
// found a quote, and we are not inside a string
array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
//print("Found start of string at {$c}\n");
} elseif (($chrs{$c} == $top['delim']) &&
($top['what'] == SERVICES_JSON_IN_STR) &&
((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
// found a quote, we're in a string, and it's not escaped
// we know that it's not escaped becase there is _not_ an
// odd number of backslashes at the end of the string so far
array_pop($stk);
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
} elseif (($chrs{$c} == '[') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-bracket, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
//print("Found start of array at {$c}\n");
} elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
// found a right-bracket, and we're in an array
array_pop($stk);
//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($chrs{$c} == '{') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-brace, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
//print("Found start of object at {$c}\n");
} elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
// found a right-brace, and we're in an object
array_pop($stk);
//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($substr_chrs_c_2 == '/*') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a comment start, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
$c++;
//print("Found start of comment at {$c}\n");
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
// found a comment end, and we're in one now
array_pop($stk);
$c++;
for ($i = $top['where']; $i <= $c; ++$i)
$chrs = substr_replace($chrs, ' ', $i, 1);
//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
}
}
if (reset($stk) == SERVICES_JSON_IN_ARR) {
return $arr;
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
return $obj;
}
}
}
}
/**
* @todo Ultimately, this should just call PEAR::isError()
*/
function isError($data, $code = null)
{
if (class_exists('pear')) {
return PEAR::isError($data, $code);
} elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
is_subclass_of($data, 'services_json_error'))) {
return true;
}
return false;
}
}
if (class_exists('PEAR_Error')) {
class Services_JSON_Error extends PEAR_Error
{
function Services_JSON_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
}
}
} else {
/**
* @todo Ultimately, this class shall be descended from PEAR_Error
*/
class Services_JSON_Error
{
function Services_JSON_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
}
}
}
?>

7102
nest-mootools.v1.11.js Normal file

File diff suppressed because it is too large Load Diff

254
nested.js Normal file
View File

@ -0,0 +1,254 @@
// Version: 1.20
// Date: 2007-01-25
// Author: CrazyDave
// Website: http://www.clanccc.co.uk/moo/nested.html
var Nested = new Class({
getOptions: function() {
return {
childTag: 'LI',
ghost: true,
childStep: 60, // attempts to become a child if the mouse is moved this number of pixels right
handleClass: null,
onStart: Class.empty,
onComplete: Class.empty,
collapse: false, // true/false
collapseClass: 'nCollapse', // Class added to collapsed items
expandKey: 'shift', // control | shift
lock: null, // parent || depth || class
lockClass: 'unlocked'
};
},
initialize: function(list, options) {
this.setOptions(this.getOptions(), options);
if (!this.options.expandKey.match(/^(control|shift)$/)) {
this.options.expandKey = 'shift';
}
this.list = $(list);
this.options.parentTag = this.list.nodeName;
this.bound = {};
this.bound.start = this.start.bindWithEvent(this);
this.list.addEvent('mousedown', this.bound.start);
if (this.options.collapse) {
this.bound.collapse = this.collapse.bindWithEvent(this);
//this.list.addEvent('click', this.bound.collapse);
}
if (this.options.initialize) this.options.initialize.call(this);
},
start: function(event) {
var el = $(event.target);
if (this.options.handleClass) {
while (el.nodeName != this.options.childTag && !el.hasClass(this.options.handleClass) && el != this.list) {
el = el.getParent();
}
if (!el.hasClass(this.options.handleClass)) return true;
}
while (el.nodeName != this.options.childTag && el != this.list) {
el = el.parentNode;
}
if (el.nodeName != this.options.childTag) return true;
el = $(el);
if (this.options.lock == 'class' && !el.hasClass(this.options.lockClass)) return;
if (this.options.ghost) { // Create the ghost
this.ghost = el.clone().setStyles({
'list-style-type': 'none',
'opacity': 0.5,
'position': 'absolute',
'visibility': 'hidden',
'top': event.page.y+'px',
'left': (event.page.x+10)+'px'
}).injectInside(document.body);
}
el.depth = this.getDepth(el);
el.moved = false;
this.bound.movement = this.movement.bindWithEvent(this, el);
this.bound.end = this.end.bind(this, el);
this.list.removeEvent('mousedown', this.bound.start);
this.list.addEvent('mousedown', this.bound.end);
this.list.addEvent('mousemove', this.bound.movement);
document.addEvent('mouseup', this.bound.end);
if (window.ie) { // IE fix to stop selection of text when dragging
this.bound.stop = this.stop.bindWithEvent(this);
$(document.body).addEvent('drag', this.bound.stop).addEvent('selectstart', this.bound.stop);
}
this.fireEvent('onStart', el);
event.stop();
},
collapse: function(event) {
var el = $(event.target);
if (this.options.handleClass) {
while (el.nodeName != this.options.childTag && !el.hasClass(this.options.handleClass) && el != this.list) {
el = el.getParent();
}
if (!el.hasClass(this.options.handleClass)) return true;
}
while (el.nodeName != this.options.childTag && el != this.list) {
el = el.parentNode;
}
if (el == this.list) return;
el = $(el);
if (!el.moved) {
var sub = $E(this.options.parentTag, el);
if (sub) {
if (sub.getStyle('display') == 'none') {
sub.setStyle('display', 'block');
el.removeClass(this.options.collapseClass);
} else {
sub.setStyle('display', 'none');
el.addClass(this.options.collapseClass);
}
}
}
event.stop();
},
stop: function(event) {
event.stop();
return false;
},
getDepth: function(el, add) {
var counter = (add) ? 1 : 0;
while (el != this.list) {
if (el.nodeName == this.options.parentTag) counter += 1;
el = el.parentNode;
}
return counter;
},
movement: function(event, el) {
var dir, over, check, items;
var dest, move, prev, prevParent;
var abort = false;
if (this.options.ghost && el.moved) { // Position the ghost
this.ghost.setStyles({
'position': 'absolute',
'visibility': 'visible',
'top': event.page.y+'px',
'left': (event.page.x+10)+'px'
});
}
over = event.target;
while (over.nodeName != this.options.childTag && over != this.list) {
over = over.parentNode;
}
if (over == this.list) return;
if (event[this.options.expandKey] && over != el && over.hasClass(this.options.collapseClass)) {
check = $E(this.options.parentTag, over);
over.removeClass(this.options.collapseClass);
check.setStyle('display', 'block');
}
// Check if it's actually inline with a child element of the event firer
orig = over;
if (el != over) {
items = $ES(this.options.childTag, over);
items.each(function(item) {
if (event.page.y > item.getTop() && item.offsetHeight > 0) over = item;
});
}
// Make sure we end up with a childTag element
if (over.nodeName != this.options.childTag) return;
// store the previous parent 'ol' to remove it if a move makes it empty
prevParent = el.getParent();
dir = (event.page.y < el.getTop()) ? 'up' : 'down';
move = 'before';
dest = el;
if (el != over) {
check = over;
while (check != null && check != el) {
check = check.parentNode;
} // Make sure we're not trying to move something below itself
if (check == el) return;
if (dir == 'up') {
move = 'before'; dest = over;
} else {
sub = $E(this.options.childTag, over);
if (sub && sub.offsetHeight > 0) {
move = 'before'; dest = sub;
} else {
move = 'after'; dest = over;
}
}
}
// Check if we're trying to go deeper -->>
prev = (move == 'before') ? dest.getPrevious() : dest;
if (prev) {
move = 'after';
dest = prev;
check = $E(this.options.parentTag, dest);
while (check && event.page.x > check.getLeft() && check.offsetHeight > 0) {
dest = check.getLast();
check = $E(this.options.parentTag, dest);
}
if (!check && event.page.x > dest.getLeft()+this.options.childStep) {
move = 'inside';
}
}
last = dest.getParent().getLast();
while (((move == 'after' && last == dest) || last == el) && dest.getParent() != this.list && event.page.x < dest.getLeft()) {
move = 'after';
dest = $(dest.parentNode.parentNode);
last = dest.getParent().getLast();
}
abort = false;
if (move != '') {
abort += (dest == el);
abort += (move == 'after' && dest.getNext() == el);
abort += (move == 'before' && dest.getPrevious() == el);
abort += (this.options.lock == 'depth' && el.depth != this.getDepth(dest, (move == 'inside')));
abort += (this.options.lock == 'parent' && (move == 'inside' || dest.parentNode != el.parentNode));
abort += (dest.offsetHeight == 0);
sub = $E(this.options.parentTag, over);
sub = (sub) ? sub.getTop() : 0;
sub = (sub > 0) ? sub-over.getTop() : over.offsetHeight;
abort += (event.page.y < (sub-el.offsetHeight)+over.getTop());
if (!abort) {
if (move == 'inside') dest = new Element(this.options.parentTag).injectInside(dest);
$(el).inject(dest, move);
el.moved = true;
if (!prevParent.getFirst()) prevParent.remove();
}
}
event.stop();
},
detach: function() {
this.list.removeEvent('mousedown', this.start.bindWithEvent(this));
if (this.options.collapse) this.list.removeEvent('click', this.bound.collapse);
},
serialize: function(listEl) {
var serial = [];
var kids;
if (!listEl) listEl = this.list;
$$(listEl.childNodes).each(function(node, i) {
kids = $E(this.options.parentTag, node);
serial[i] = {
id: node.id,
hide: (node.hasClass('remove')) ? 'exclude' : "",
children: (kids) ? this.serialize(kids) : []
};
}.bind(this));
return serial;
},
end: function(el) {
if (this.options.ghost) this.ghost.remove();
this.list.removeEvent('mousemove', this.bound.movement);
document.removeEvent('mouseup', this.bound.end);
this.list.removeEvent('mousedown', this.bound.end);
this.list.addEvent('mousedown', this.bound.start);
this.fireEvent('onComplete', el);
if (window.ie) $(document.body).removeEvent('drag', this.bound.stop).removeEvent('selectstart', this.bound.stop);
}
});
Nested.implement(new Events);
Nested.implement(new Options);

BIN
page.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

View File

@ -4,29 +4,42 @@ Plugin Name: pageMash
Plugin URI: http://joelstarnes.co.uk/pagemash/
Description: pageMash > pageManagement [WP_Admin > Manage > pageMash]
Author: Joel Starnes
Version: 0.1.3
Version: 1.0.0
Author URI: http://joelstarnes.co.uk/
CHANGELOG:
Release: Date: Description:
0.1.0 10 Feb 2008 Initial release
0.1.1 12 Feb 2008 Fixed Removed external include
0.1.2 15 Feb 2008 Fixed CSS&JS headers to only display on pagemash
0.1.3 19 Feb 2008 Fixed exclude pages feature
0.1.1 12 Feb 2008 Minor fixes > Removed external include
0.1.2 15 Feb 2008 Minor fixes > Fixed CSS&JS headers to only display on pagemash
1.0.0 beta 19 Feb 2008 Major update > Recusive page handles unlimited nested children,
collapsable list items, interface makeover...
TODO:
@todo optimize for instantUpdateFeature
@todo update moo code?
@todo default exclude pages off / write toggle option?
@todo svn branch?
@todo release in beta
FIXME:
@fixme with instantUpdateFeature hide will not send the update
*/
#########CONFIG OPTIONS############################################
$minlevel = 7; /*[deafult=7]*/
/* Minimum user level to access page order */
$excludePagesFeature = false; /*[deafult=true]*/
/* Allows you to set pages not to be listed
Will only work if you have modified the template. */
$instantUpdateFeature = false; /*[deafult=false]*/
/* Updates the database instantly after a move using ajax
otherwise it will wait for update button press.
nb. enabling this feature will put strain on the mysql server */
nb. this feature has not been optimised and enabling will cause
much increased server load */
$excludePagesFeature = true; /*[deafult=true]*/
/* Allows you to set pages not to be listed
Will only work if you have modified the template. */
###################################################################
/*
CREDITS:
@ -53,41 +66,68 @@ ShiftThis - WP Page Order Plugin [http://www.shiftthis.net/wordpress-order-pages
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
function pageMash_main(){
global $wpdb, $wp_version, $instantUpdateFeature, $excludePagesFeature;
//get pages from database
if($wp_version >= 2.1){
$pageposts = $wpdb->get_results("SELECT * FROM $wpdb->posts WHERE post_type = 'page' AND post_parent = '0' ORDER BY menu_order");
function pageMash_getPages($post_parent){
//this is a recurrsive function which calls itself to produce a nested list of elements
//$post_parent should be 0 for root pages, or contain a pageID to return it's sub-pages
global $wpdb, $wp_version, $instantUpdateFeature, $excludePagesFeature, $excludePagesList;
if($wp_version >= 2.1){ //get pages from database
$pageposts = $wpdb->get_results("SELECT * FROM $wpdb->posts WHERE post_type = 'page' AND post_parent = '$post_parent' ORDER BY menu_order");
}else{
$pageposts = $wpdb->get_results("SELECT * FROM $wpdb->posts WHERE post_status = 'static' AND post_parent = '0' ORDER BY menu_order");
$pageposts = $wpdb->get_results("SELECT * FROM $wpdb->posts WHERE post_status = 'static' AND post_parent = '$post_parent' ORDER BY menu_order");
}
//get pages set to exclude
$excludePagesList = '>,'.get_option('exclude_pages');
//precede with '>,' otherwise the first pageid will return 0 when strpos() is called to find it.
//the initial coma allows us to search for ',$pageid,' so as to avoid partial matches
if ($pageposts == true){ //if $pageposts == true then it does have sub-page(s), so list them.
echo '<ul ';
if($post_parent==0) echo 'id="pageMash_pages" '; //add this ID only to root 'ul' element
echo 'style="list-style:none;">';
foreach ($pageposts as $page): //list pages, [the 'li' ID must be the page ID] ?>
<li id="pm_<?=$page->ID;?>" <?php if(strpos($excludePagesList, ','.$page->ID.',')){echo 'class="remove"';}//if page is in exclude list, add class remove ?>>
<span class="title"><?=$page->post_title;?></span>
<span class="pageMash_pageFunctions">
id:<?=$page->ID;?>
[<a href="<?=get_settings('siteurl').'/wp-admin/post.php?action=edit&post='.$page->ID; ?>" title="Edit This Page">edit</a>]
<?php if($excludePagesFeature): ?>
[<a href="#" title="Show|Hide" class="excludeLink" onclick="toggleRemove(this);">hide</a>]
<?php endif; ?>
</span>
<?php pageMash_getPages($page->ID) //call this function to list any sub-pages (passing it the pageID) ?>
</li>
<?php endforeach;
echo '</ul>';
return true;
} else {
return false;
}
}
function pageMash_main(){
global $wpdb, $wp_version, $instantUpdateFeature, $excludePagesFeature, $excludePagesList;
//get pages-to-hide from database
$excludePagesObj = $wpdb->get_results("SELECT option_value FROM $wpdb->options WHERE option_name = 'exclude_pages'");
$excludePagesList = '>,'.$excludePagesObj[0]->option_value;
//precede with '>,' otherwise the first pageid will return 0 when strpos() is called to find it.
//the initial coma allows us to search for ',$pageid,' so as to avoid partial matches
?>
<div id="debug_list"></div>
<div id="pageMash" class="wrap">
<div id="pageMash_checkVersion" style="float:right; font-size:.7em; margin-top:5px;">
version [0.1.3]
version [1.0.0 beta]
</div>
<h2 style="margin-bottom:0; clear:none;">pageMash - pageManagement</h2>
<p style="margin-top:4px;">You can use this to organise and manage your pages. </p>
<ul id="pageMash_pages" style="list-style:none;">
<?php foreach ($pageposts as $page): //list pages ?>
<li id="<?=$page->ID;?>" <?php if(strpos($excludePagesList, ','.$page->ID.',')){echo 'class="remove"';}//if page is in exclude list, add class remove ?>>
<strong><?=$page->post_title;?></strong>
[<a href="<?=get_option('siteurl').'/wp-admin/post.php?action=edit&post='.$page->ID; ?>" title="Edit This Page">edit</a>]
</li>
<?php endforeach; ?>
</ul>
<p style="margin-top:4px;">
Just drag the pages <strong>up</strong> or <strong>down</strong> to change the page order and <strong>left</strong> or <strong>right</strong> to change the page's parent, then hit 'update'.<br />
The icon to the left of each page shows if it has child pages, <strong>double click</strong> anywhere on that item to toggle <strong>expand|collapse</strong> of it's children.
</p>
<div>
<?php pageMash_getPages(0); //pass 0, as initial parent ?>
</div>
<p class="submit">
<span id="update_status" style="float:left; margin-left:40px; opacity:0;"></span>
<div id="update_status" style="float:left; margin-left:40px; opacity:0;"></div>
<?php if(!$instantUpdateFeature): ?>
<input type="submit" id="pageMash_submit" tabindex="2" style="font-weight: bold; float:right;" value="Update" name="submit"/>
<?php endif; ?>
@ -97,53 +137,102 @@ function pageMash_main(){
<div class="wrap" style="width:160px; margin-bottom:0; padding:2px; text-align:center;"><a href="#" id="pageMashInfo_toggle" style="text-align:center;">Show|Hide Further Info</a></div>
<div class="wrap" id="pageMashInfo" style="margin-top:-1px;">
<h2>How to</h2>
<h4 style="margin-bottom:0;">Just drag the pages into the order you like, hit 'update' and enjoy the scrummy ajaxified goodness.</h4>
<p style="margin-top:0;">
<?php if($excludePagesFeature): ?>
Click the little red icon to left of each page to hide that page or press the 'edit' button to edit that page. Sorted.<br />
<?php endif; ?>
<small><strong>Note:</strong> This plugin only orders top level pages</small>
</p>
<p style="margin-bottom:1px;">To use this plugin you need to use the <strong>wp_list_pages()</strong> function with the parameters as shown below:</p>
<code id="pageMash_code">
<span class="white">&lt;?php</span> <span class="purple">if(</span><span class="blue">function_exists(</span><span class="orange">'pageMash_exclude_pages'</span><span class="blue">)</span><span class="purple">){</span><span class="yellow">$exclude_pages</span><span class="white">=</span><span class="blue">pageMash_exclude_pages();</span><span class="purple">} else{</span><span class="yellow">$exclude_pages</span><span class="white">=</span><span class="orange">''</span><span class="blue">;</span><span class="purple">}</span><span class="white">?&gt;</span><br />
<span class="white">&lt;?php</span> <span class="blue">wp_list_pages(</span><span class="orange">'title_li=&lt;h2&gt;Pages&lt;/h2&gt;&amp;exclude='</span><span class="green">.</span><span class="yellow">$exclude_pages</span><span class="blue">);</span><span class="white">?&gt;</span>
<h2>How to Install</h2>
<p style="font-size:1.1em;">In most cases, to use this plugin you will not need to change anything, however if its not working you will either need to:</p>
<ol>
<li>Check your 'pages' widget in the WP admin panel under the Presentation>Widgets tab and click the little icon on the pages widget and ensure that <strong>sort by</strong> is set to <strong>'page order'</strong>. </li>
<li>If you want the pages listed else-where or do not use the widgets or want you would like to use the excludePagesFeature, then you need to edit your template as shown below:
<ol style="list-style-type:upper-roman;">
<li style="margin-bottom:0;">To use the code in your sidebar.php file you need to remove all widgets in your WP admin to active the sidebar code and then find the <strong>wp_list_pages()</strong> function and change it to the code below </li>
<li style="margin-bottom:0;">To insert the pages in your header; modify header.php insert the code anywhere inside the body tag. (You may want to add the depth=1 parameter on the 2nd line if you only want top level pages listed)</li>
</ol>
Then to enable the excludePagesFeature find the line $excludePagesFeature = false; near the top of pagemash.php and change the value to true.
</li>
</ol>
<p style="margin-bottom:0; font-weight:bold;">Code:</p>
<code>
<span class="white">&lt;?php</span> <span class="purple">if(</span><span class="blue">function_exists(</span><span class="orange">'pageMash_exclude_pages'</span><span class="blue">)</span><span class="purple">){</span><span class="yellow">$exclude_pages</span><span class="white">=</span><span class="blue">pageMash_exclude_pages();</span><span class="purple">} else{</span><span class="yellow">$exclude_pages</span><span class="white">=</span><span class="orange">''</span><span class="blue">;</span><span class="purple">}</span><span class="white">?&gt;</span><br />
<span class="white">&lt;?php</span> <span class="blue">wp_list_pages(</span><span class="orange">'title_li=&lt;h2&gt;Pages&lt;/h2&gt;&amp;exclude='</span><span class="green">.</span><span class="yellow">$exclude_pages</span><span class="blue">);</span><span class="white">?&gt;</span>
</code>
<p>For more information on the wp_list_pages() function checkout the <a href="http://codex.wordpress.org/Template_Tags/wp_list_pages" title="wp_list_pages Documentation">Wordpress Codex</a> and if you have any further questions, just <a href="http://joelstarnes.co.uk/contact/" title="email Joel Starnes">drop me an email</a>.</p>
<p>The plugin code is very simple and flexible, for more information look at the wp_list_pages() function on the <a href="http://codex.wordpress.org/Template_Tags/wp_list_pages" title="wp_list_pages Documentation">Wordpress Codex</a> and if you have any further questions or feedback, just <a href="http://joelstarnes.co.uk/contact/" title="email Joel Starnes">drop me an email</a>.</p>
</div>
<?php
}
function pageMash_head(){
if(strrpos('>'.$_GET["page"], 'pagemash')){ // only include header stuff on pagemash admin page
if(strrpos('>'.$_GET["page"], 'pagemash')): // only include header stuff on pagemash admin page
//stylesheet & javascript to go in page header
global $instantUpdateFeature, $excludePagesFeature;
?>
<style type="text/css">
ul#pageMash_pages li { display:block; margin:2px 0 0 0; border-bottom:1px solid #aaa; border-right:1px solid #aaa; border-top:1px solid #ccc; border-left:1px solid #ccc; padding:5px 6px; background-color:#F1F1F1; }
body { overflow-y:scroll; }
span#update_status { font-weight:bold; }
ul#pageMash_pages li.remove { color:grey; border-style:dashed;}
ul#pageMash_pages {
margin:0 0 0 0;
}
ul#pageMash_pages li.collapsed ul {
display:none;
}
ul#pageMash_pages li.children {
background-image: url('<?=get_settings("siteurl")?>/wp-content/plugins/pagemash/collapse.png');
}
ul#pageMash_pages li.collapsed.children {
background-image: url('<?=get_settings("siteurl")?>/wp-content/plugins/pagemash/expand.png');
}
ul#pageMash_pages li {
display:block;
margin:2px 0 0 0;
border-bottom:1px solid #aaa; border-right:1px solid #aaa; border-top:1px solid #ccc; border-left:1px solid #ccc;
padding:4px 6px 4px 24px;
background:#F1F1F1 url('<?=get_settings("siteurl")?>/wp-content/plugins/pagemash/page.png') no-repeat 4px 4px;
list-style-type:none;
}
ul#pageMash_pages li span.title {
font-weight: bold;
}
ul#pageMash_pages li.collapsed.children span.title {
text-decoration: underline;
}
#update_status {
font-weight:bold;
display:block;
border:2px solid #AC604C;
background-color: #DDA37A;
padding: 2px 6px;
}
ul#pageMash_pages li.remove { color:grey; border-style:dashed; opacity:.5;}
ul#pageMash_pages li.remove a { color:grey; }
ul#pageMash_pages li.remove img { opacity:0.2; }
ul#pageMash_pages li span.pageMash_pageFunctions {
border:1px solid #ccc;
background-color: #eee;
padding: 1px 3px;
}
ul#pageMash_pages li span.pageMash_pageFunctions a { border:0; }
#pageMash_code {display:block; border:solid 3px #858EF4; background-color:#211E1E; padding:7px; margin=10px;}
#pageMash_code .white{color:#DADADA;}
#pageMash_code .purple{color:#9B2E4D; font-weight:bold;}
#pageMash_code .green{color:#00FF00;}
#pageMash_code .blue{color:#858EF4;}
#pageMash_code .yellow{color:#C1C144;}
#pageMash_code .orange{color:#EC9E00;}
ul#pageMash_pages li span.pageMash_pageFunctions { display:none; }
ul#pageMash_pages li:hover span.pageMash_pageFunctions { display:inline; }
ul#pageMash_pages li:hover li span.pageMash_pageFunctions { display:none; }
ul#pageMash_pages li:hover li:hover span.pageMash_pageFunctions { display:inline; }
ul#pageMash_pages li:hover li:hover li span.pageMash_pageFunctions { display:none; }
ul#pageMash_pages li:hover li:hover li:hover span.pageMash_pageFunctions { display:inline; }
ul#pageMash_pages li:hover li:hover li:hover li span.pageMash_pageFunctions { display:none; }
ul#pageMash_pages li:hover li:hover li:hover li:hover span.pageMash_pageFunctions { display:inline; }
ul#pageMash_pages li:hover li:hover li:hover li:hover li span.pageMash_pageFunctions { display:none; }
ul#pageMash_pages li:hover li:hover li:hover li:hover li:hover span.pageMash_pageFunctions { display:inline; }
code {display:block; border:solid 3px #858EF4; background-color:#211E1E; padding:7px; margin:0px;}
code .white{color:#DADADA;}
code .purple{color:#9B2E4D; font-weight:bold;}
code .green{color:#00FF00;}
code .blue{color:#858EF4;}
code .yellow{color:#C1C144;}
code .orange{color:#EC9E00;}
</style>
<script type="text/javascript" src="<?=get_option('siteurl')?>/wp-content/plugins/pagemash/mootools-1.11.js"></script>
<!-- Current JSON ajax code not compatible with newer releases of moo -->
<script type="text/javascript" src="<?=get_settings('siteurl')?>/wp-content/plugins/pagemash/nest-mootools.v1.11.js"></script>
<script type="text/javascript" src="<?=get_settings('siteurl')?>/wp-content/plugins/pagemash/nested.js"></script>
<script type="text/javascript">
/* Moo extenders */
/* add timeout to Ajax class */
Ajax = Ajax.extend({
/* add timeout to Ajax class */
request: function(){
if (this.options.timeout) {
this.timeoutTimer=window.setTimeout(this.callTimeout.bindAsEventListener(this), this.options.timeout);
@ -162,57 +251,77 @@ Ajax = Ajax.extend({
window.clearTimeout(this.timeoutTimer);
}
});
var MySortables = Sortables.extend({
/* clicking links should not start the drag, but fire the link's event */
start: function(event, element) {
if (event.target.tagName != 'A' && event.target.tagName != 'IMG') {
this.parent(event, element);
}
}
});
window.addEvent('domready', function(){
var mySort = new MySortables($('pageMash_pages'), {
cloneOpacity:.2,
onComplete: function(){
/* alternate list colour & if($instantUpdateFeature) ajax db update */
<?php if($instantUpdateFeature): ?>updateOrder( mySort.serialize() );<?php endif; ?>
mySort.altColor();
}
});
Sortables.implement({
serialize: function(){
/* go through each element of list and return array of element IDs */
var serial = [];
this.list.getChildren().each(function(el, i){
serial[i] = el.getProperty('id');
}, this);
return serial;
/* function to retrieve list data and send to server in JSON format */
var SaveList = function() {
var theDump = sortIt.serialize();
new Ajax('<?=get_settings("siteurl")?>/wp-content/plugins/pagemash/saveList.php', {
method: 'post',
postBody: 'm='+Json.toString(theDump),
/* update: "debug_list", */
onComplete: function() {
$('update_status').setText('Database Updated');
new Fx.Style($('update_status'), 'opacity', {duration: 500}).start(0,1).chain(function() {
new Fx.Style($('update_status'), 'opacity', {duration: 1500}).start(1,0);
});
},
timeout: 5500,
onTimeout: function() {
$('update_status').setText('Error: Update Timeout');
new Fx.Style($('update_status'), 'opacity', {duration: 200}).start(0,1);
}
}).request();
};
/* toggle the remove class of grandparent */
<?php if($excludePagesFeature): ?>
var toggleRemove = function(el) {
el.parentNode.parentNode.toggleClass('remove');
}
<?php endif; ?>
/* ******** dom ready ******** */
window.addEvent('domready', function(){
sortIt = new Nested('pageMash_pages', {
collapse: true,
onComplete: function(el) {
el.setStyle('background-color', '#F1F1F1');
sortIt.altColor();
<?php if($instantUpdateFeature): ?>SaveList();<?php endif; ?>
$ES('li','pageMash_pages').each(function(el) {
if( el.getElement('ul') ){
el.addClass('children');
} else {
el.removeClass('children');
}
});
}
});
Nested.implement({
/* alternate the colours of top level nodes */
altColor: function(){
/* alternate the list colour */
var odd = 1;
this.list.getChildren().each(function(element, i){
if(odd==1){
odd=0;
element.setStyle('background-color', '#F1F1F1');
element.setStyle('background-color', '#CFE8A8');
}else{
odd=1;
element.setStyle('background-color', '#FFFFFF');
element.setStyle('background-color', '#D8E8E6');
}
});
}
});
mySort.altColor();
sortIt.altColor();
$('update_status').setStyle('opacity', 0);
<?php if(!$instantUpdateFeature): ?>
$('pageMash_submit').addEvent('click', function(e){
e = new Event(e);
updateOrder( mySort.serialize() );
SaveList();
e.stop();
});
<?php endif; ?>
<?php endif; ?>
var pageMashInfo = new Fx.Slide('pageMashInfo');
$('pageMashInfo_toggle').addEvent('click', function(e){
@ -231,47 +340,25 @@ window.addEvent('domready', function(){
pageMashInfo.hide();
$('pageMashInfo_toggle').setText('Show Further Info');
<?php if($excludePagesFeature): ?>
$ES('li','pageMash_pages').each(function(el) { DeleteButton(el); })
<?php endif; ?>
}); /* close dom ready */
function updateOrder (serial) {
<?php if($excludePagesFeature): ?>
var excludePages = "";
$$('#pageMash_pages li.remove').each(function(el){
excludePages += el.getProperty('id') + ',';
/* loop through each page */
$ES('li','pageMash_pages').each(function(el) {
/* If the li has a 'ul' child; it has children pages */
if( el.getElement('ul') ) el.addClass('children');
/* on page dblClick add this event */
el.addEvent('dblclick', function(e){
e = new Event(e);
if(el.hasClass('children')) el.toggleClass('collapsed');
e.stop();
});
<?php endif; ?>
new Ajax('<?=get_option('siteurl')?>/wp-content/plugins/pagemash/reorder.php?order='+serial+'&exclude='+excludePages, {
method: 'get',
onComplete: function() {
$('update_status').setText('Database Updated');
new Fx.Style($('update_status'), 'opacity', {duration: 300}).start(0,1).chain(function() {
new Fx.Style($('update_status'), 'opacity', {duration: 1400}).start(1,0);
});
},
timeout: 5500,
onTimeout: function() {
$('update_status').setText('Error: Update Timeout');
new Fx.Style($('update_status'), 'opacity', {duration: 200}).start(0,1);
}
}).request();
}
<?php if($excludePagesFeature): ?>
var DeleteButton = function(el) {
new Element('img').setProperties({src: '<?=get_option("siteurl")?>/wp-content/plugins/pagemash/hide.png', alt: 'show|hide'}).addEvent('click', toggleRemove).injectTop(el);
}
var toggleRemove = function() {
this.parentNode.toggleClass('remove');
}
<?php endif; ?>
});
}); /* close dom ready */
</script>
<?php
} //end main if
} //end function
endif; //main function only display head if jmash admin page
}
function pageMash_add_pages(){
@ -289,4 +376,6 @@ function pageMash_exclude_pages(){
add_action('admin_menu', 'pageMash_add_pages'); //add admin menu under management tab
add_action('admin_head', 'pageMash_head'); //add css styles and JS code to head
?>

44
saveList.php Normal file
View File

@ -0,0 +1,44 @@
<?php
error_reporting(E_ALL);
require('myjson.php'); //JSON decode lib
require('./../../../wp-config.php'); //config to connect to database
global $wpdb, $excludePages;
$excludePages = "";
// fetch JSON object from $_POST['m']
$json = new Services_JSON();
$aMenu = (array) $json->decode(stripslashes($_POST['m']));
function saveList($parent, $children) {
global $wpdb, $excludePages;
$parent = (int) $parent;
$result = array();
$i = 1;
foreach ($children as $k => $v) {
//IDs are 'JM_#' so strip first 3 characters
$id = (int) substr($children[$k]->id, 3);
//if it had the remove class it is now added to the excludePages var
if($v->hide=='exclude') $excludePages .= $id.',';
//update pages in db
$postquery = "UPDATE $wpdb->posts SET menu_order='$i', post_parent='$parent' WHERE ID='$id'";
$wpdb->query($postquery);
echo $postquery;
echo "\n";
if (isset($v->children[0])) {saveList($id, $v->children);}
$i++;
}
}
echo saveList(0, $aMenu);
//update excludePages option in database
update_option("exclude_pages", $excludePages, '', 'yes');
?>