aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engine/classes/ElggPriorityList.php384
-rw-r--r--engine/lib/elgglib.php112
-rw-r--r--engine/tests/api/helpers.php323
3 files changed, 789 insertions, 30 deletions
diff --git a/engine/classes/ElggPriorityList.php b/engine/classes/ElggPriorityList.php
new file mode 100644
index 000000000..931138106
--- /dev/null
+++ b/engine/classes/ElggPriorityList.php
@@ -0,0 +1,384 @@
+<?php
+/**
+ * Iterate over elements in a specific priority.
+ *
+ * You can add, remove, and access elements using OOP or array interfaces:
+ *
+ * // OOP
+ * $pl = new ElggPriorityList();
+ * $pl->add('Element 0');
+ * $pl->add('Element -5', -5);
+ * $pl->add('Element 10', 10);
+ * $pl->add('Element -10', -10);
+ *
+ * $pl->remove('Element -5');
+ *
+ * $elements = $pl->getElements();
+ * var_dump($elements);
+ *
+ * Yields:
+ *
+ * array(
+ * -10 => 'Element -10',
+ * 0 => 'Element 0',
+ * 10 => 'Element 10',
+ * )
+ *
+ *
+ * // Array
+ *
+ * $pl = new ElggPriorityList();
+ * $pl[] = 'Element 0';
+ * $pl[-5] = 'Element -5';
+ * $pl[10] = 'Element 10';
+ * $pl[-10] = 'Element -10';
+ *
+ * $priority = $pl->getPriority('Element -5');
+ * unset($pl[$priority]);
+ *
+ * foreach ($pl as $priority => $element) {
+ * var_dump("$priority => $element");
+ * }
+ *
+ * Yields:
+ * -10 => Element -10
+ * 0 => Element 0
+ * 10 => Element 10
+ *
+ *
+ * Collisions with priority are handled by default differently in the OOP and the array interfaces.
+ *
+ * If using the OOP interface, the default is to insert the element as close to the requested
+ * priority as possible.
+ *
+ * $pl = new ElggPriorityList();
+ * $pl->add('Element 5', 5);
+ * $pl->add('Colliding element 5', 5);
+ * $pl->add('Another colliding element 5', 5);
+ *
+ * var_dump($pl->getElements());
+ *
+ * Yields:
+ * array(
+ * 5 => 'Element 5',
+ * 6 => 'Colliding element 5',
+ * 7 => 'Another colliding element 5'
+ * )
+ *
+ * If using the array interface, elements are added at exactly the priority, displacing other
+ * elements if necessary. This behavior is also available by passing true as the 3rd argument to
+ * ->add():
+ *
+ * $pl = new ElggPriorityList();
+ * $pl[5] = 'Element 5';
+ * $pl[6] = 'Element 6';
+ * $pl[5] = 'Colliding element 5'; // shifts the previous two up by one
+ * $pl->add('Another colliding element 5', 5, true); // shifts the previous three up by one
+ *
+ * var_dump($pl->getElements());
+ *
+ * Yields:
+ * array(
+ * 5 => 'Another colliding element 5',
+ * 6 => 'Colliding element 5',
+ * 7 => 'Element 5',
+ * 8 => 'Element 6'
+ * )
+ *
+ * @package Elgg.Core
+ * @subpackage Helpers
+ */
+
+class ElggPriorityList
+ implements Iterator, ArrayAccess, Countable {
+
+ /**
+ * The list of elements
+ *
+ * @var array
+ */
+ private $elements = array();
+
+ /**
+ * Create a new priority list.
+ *
+ * @param array $elements An optional array of priorities => element
+ */
+ public function __construct(array $elements = array()) {
+ if ($elements) {
+ foreach ($elements as $priority => $element) {
+ $this->add($element, $priority);
+ }
+ }
+ }
+
+ /**
+ * Adds an element to the list.
+ *
+ * @warning This returns the priority at which the element was added, which can be 0. Use
+ * !== false to check for success.
+ *
+ * @param mixed $element The element to add to the list.
+ * @param mixed $priority Priority to add the element. In priority collisions, the original element
+ * maintains its priority and the new element is to the next available
+ * slot, taking into consideration all previously registered elements.
+ * Negative elements are accepted.
+ * @param bool $exact If true, will put the element at exactly the priority specified, displacing
+ * other elements.
+ * @return int The priority of the added element.
+ */
+ public function add($element, $priority = null, $exact = false) {
+ if ($priority !== null && !is_numeric($priority)) {
+ return false;
+ } elseif ($exact) {
+ $this->shiftElementsSegment($priority);
+ } else {
+ $priority = $this->getNextPriority($priority);
+ }
+
+ $this->elements[$priority] = $element;
+ $this->sorted = false;
+ return $priority;
+ }
+
+ /**
+ * Removes an element from the list.
+ *
+ * @warning The element must have the same attributes / values. If using $strict, it must have
+ * the same types. array(10) will fail in strict against array('10') (str vs int).
+ *
+ * @param type $element
+ * @return bool
+ */
+ public function remove($element, $strict = false) {
+ $index = array_search($element, $this->elements, $strict);
+ if ($index !== false) {
+ unset($this->elements[$index]);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Move an existing element to a new priority.
+ *
+ * @param int $current_priority
+ * @param int $new_priority
+ * @param bool $exact
+ * @return bool
+ */
+ public function move($current_priority, $new_priority, $exact = false) {
+ $current_priority = (int) $current_priority;
+ $new_priority = (int) $new_priority;
+
+ if (!isset($this->elements[$current_priority])) {
+ return false;
+ }
+
+ if ($current_priority == $new_priority) {
+ return true;
+ }
+
+ $element = $this->elements[$current_priority];
+ unset($this->elements[$current_priority]);
+
+ return $this->add($element, $new_priority, $exact);
+ }
+
+ /**
+ * Returns the elements
+ *
+ * @param type $elements
+ * @param type $sort
+ */
+ public function getElements() {
+ $this->sortIfUnsorted();
+ return $this->elements;
+ }
+
+ /**
+ * Sort the elements optionally by a callback function.
+ *
+ * If no user function is provided the elements are sorted by priority registered.
+ *
+ * The callback function should accept the array of elements as the first argument and should
+ * return a sorted array.
+ *
+ * This function can be called multiple times.
+ *
+ * @param type $callback
+ * @return bool
+ */
+ public function sort($callback = null) {
+ if (!$callback) {
+ ksort($this->elements, SORT_NUMERIC);
+ } else {
+ $sorted = call_user_func($callback, $this->elements);
+
+ if (!$sorted) {
+ return false;
+ }
+
+ $this->elements = $sorted;
+ }
+
+ $this->sorted = true;
+ return true;
+ }
+
+ /**
+ * Sort the elements if they haven't been sorted yet.
+ *
+ * @return bool
+ */
+ private function sortIfUnsorted() {
+ if (!$this->sorted) {
+ return $this->sort();
+ }
+ }
+
+ /**
+ * Shift a segment of elements starting at $index up by one until the end of the array or
+ * there's a gap in the indexes. This produces a space at $index to insert a new element.
+ *
+ * @param type $index The index to start
+ * @return array
+ */
+ private function shiftElementsSegment($index) {
+ $index = (int) $index;
+ // @todo probably a better way.
+ $replace_elements = array();
+ while (isset($this->elements[$index])) {
+ $replace_elements[$index + 1] = $this->elements[$index];
+ unset($this->elements[$index]);
+ $index++;
+ }
+
+ // insert old ones
+ foreach ($replace_elements as $index => $element) {
+ $this->elements[$index] = $element;
+ }
+ }
+
+ /**
+ * Returns the next priority available.
+ *
+ * @param int $near Make the priority as close to $near as possible.
+ * @return int
+ */
+ public function getNextPriority($near = 0) {
+ $near = (int) $near;
+
+ while (array_key_exists($near, $this->elements)) {
+ $near++;
+ }
+
+ return $near;
+ }
+
+
+ /**
+ * Returns the priority of an element if it exists in the list.
+ *
+ * @warning This can return 0 if the element's priority is 0. Use identical operator (===) to
+ * check for false if you want to know if an element exists.
+ *
+ * @param mixed $element
+ * @return mixed False if the element doesn't exists, the priority if it does.
+ */
+ public function getPriority($element, $strict = false) {
+ return array_search($element, $this->elements, $strict);
+ }
+
+ /**********************
+ * Interfaces methods *
+ **********************/
+
+
+ /**
+ * Iterator
+ */
+
+ /**
+ * PHP Iterator Interface
+ *
+ * @see Iterator::rewind()
+ * @return void
+ */
+ public function rewind() {
+ $this->sortIfUnsorted();
+ return rewind($this->elements);
+ }
+
+ /**
+ * PHP Iterator Interface
+ *
+ * @see Iterator::current()
+ * @return mixed
+ */
+ public function current() {
+ $this->sortIfUnsorted();
+ return current($this->elements);
+ }
+
+ /**
+ * PHP Iterator Interface
+ *
+ * @see Iterator::key()
+ * @return int
+ */
+ public function key() {
+ $this->sortIfUnsorted();
+ return key($this->elements);
+ }
+
+ /**
+ * PHP Iterator Interface
+ *
+ * @see Iterator::next()
+ * @return mixed
+ */
+ public function next() {
+ $this->sortIfUnsorted();
+ return next($this->elements);
+ }
+
+ /**
+ * PHP Iterator Interface
+ *
+ * @see Iterator::valid()
+ * @return bool
+ */
+ public function valid() {
+ $this->sortIfUnsorted();
+ $key = key($this->elements);
+ return ($key !== NULL && $key !== FALSE);
+ }
+
+ // Coutable
+ public function count() {
+ return count($this->elements);
+ }
+
+ // ArrayAccess
+ public function offsetExists($offset) {
+ return isset($this->elements[$offset]);
+ }
+
+ public function offsetGet($offset) {
+ return isset($this->elements[$offset]) ? $this->elements[$offset] : null;
+ }
+
+ public function offsetSet($offset, $value) {
+ // for $pl[] = 'New element'
+ $exact = ($offset !== null);
+ return $this->add($value, $offset, $exact);
+ }
+
+ public function offsetUnset($offset) {
+ if (isset($this->elements[$offset])) {
+ unset($this->elements[$offset]);
+ }
+ }
+} \ No newline at end of file
diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php
index cb736f418..b6b603e79 100644
--- a/engine/lib/elgglib.php
+++ b/engine/lib/elgglib.php
@@ -172,7 +172,7 @@ function forward($location = "", $reason = 'system') {
* @return bool
* @since 1.8.0
*/
-function elgg_register_js($name, $url, $location = 'head', $priority = 500) {
+function elgg_register_js($name, $url, $location = 'head', $priority = null) {
return elgg_register_external_file('js', $name, $url, $location, $priority);
}
@@ -225,7 +225,7 @@ function elgg_get_loaded_js($location = 'head') {
* @return bool
* @since 1.8.0
*/
-function elgg_register_css($name, $url, $priority = 500) {
+function elgg_register_css($name, $url, $priority = null) {
return elgg_register_external_file('css', $name, $url, 'head', $priority);
}
@@ -278,7 +278,7 @@ function elgg_get_loaded_css() {
* @return bool
* @since 1.8.0
*/
-function elgg_register_external_file($type, $name, $url, $location, $priority = 500) {
+function elgg_register_external_file($type, $name, $url, $location, $priority = null) {
global $CONFIG;
if (empty($name) || empty($url)) {
@@ -292,26 +292,35 @@ function elgg_register_external_file($type, $name, $url, $location, $priority =
$CONFIG->externals = array();
}
- if (!isset($CONFIG->externals[$type])) {
- $CONFIG->externals[$type] = array();
+ if (!$CONFIG->externals[$type] instanceof ElggPriorityList) {
+ $CONFIG->externals[$type] = new ElggPriorityList();
}
$name = trim(strtolower($name));
+ $priority = max((int)$priority, 0);
- if (isset($CONFIG->externals[$type][$name])) {
- // update a registered item
- $item = $CONFIG->externals[$type][$name];
+ $index = elgg_get_external_file_priority($name, $type);
+
+ if ($index !== false) {
+ // updating a registered item
+ $item = $CONFIG->externals[$type][$index];
+ $item->url = $url;
+ $item->location = $location;
+ // remove old saved priority
+ elgg_remove_external_file_priority($name, $type);
+ $priority = $CONFIG->externals[$type]->move($index, $priority);
} else {
$item = new stdClass();
$item->loaded = false;
- }
+ $item->url = $url;
+ $item->location = $location;
- $item->url = $url;
- $item->priority = max((int)$priority, 0);
- $item->location = $location;
+ $priority = $CONFIG->externals[$type]->add($item, $priority);
+ }
- $CONFIG->externals[$type][$name] = $item;
+ // save priority map so we can update if added again
+ elgg_save_external_file_priority($priority, $name, $type);
return true;
}
@@ -332,14 +341,17 @@ function elgg_unregister_external_file($type, $name) {
return false;
}
- if (!isset($CONFIG->externals[$type])) {
+ if (!$CONFIG->externals[$type] instanceof ElggPriorityList) {
return false;
}
$name = trim(strtolower($name));
- if (array_key_exists($name, $CONFIG->externals[$type])) {
- unset($CONFIG->externals[$type][$name]);
+ $priority = elgg_get_external_file_priority($name, $type);
+
+ if ($priority !== false) {
+ elgg_remove_external_file_priority($name, $type);
+ unset($CONFIG->externals[$type][$priority]);
return true;
}
@@ -362,24 +374,75 @@ function elgg_load_external_file($type, $name) {
$CONFIG->externals = array();
}
- if (!isset($CONFIG->externals[$type])) {
- $CONFIG->externals[$type] = array();
+ if (!$CONFIG->externals[$type] instanceof ElggPriorityList) {
+ $CONFIG->externals[$type] = new ElggPriorityList();
}
$name = trim(strtolower($name));
- if (isset($CONFIG->externals[$type][$name])) {
+ $priority = elgg_get_external_file_priority($name, $type);
+
+ if ($priority !== false) {
// update a registered item
- $CONFIG->externals[$type][$name]->loaded = true;
+ $CONFIG->externals[$type][$priority]->loaded = true;
} else {
$item = new stdClass();
$item->loaded = true;
$item->url = '';
$item->location = '';
- $item->priority = 500;
- $CONFIG->externals[$type][$name] = $item;
+ $priority = $CONFIG->externals[$type]->add($item);
+ elgg_save_external_file_priority($priority, $name, $type);
+ }
+}
+
+/**
+ * Gets the priority of an external by name and type.
+ *
+ * @param type $name
+ * @param type $type
+ * @return type
+ */
+function elgg_get_external_file_priority($name, $type) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->externals_priorities[$type][$name])) {
+ return false;
+ }
+
+ return $CONFIG->externals_priorities[$type][$name];
+}
+
+function elgg_save_external_file_priority($priority, $name, $type) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->externals_priorities)) {
+ $CONFIG->externals_priorities = array();
+ }
+
+ if (!isset($CONFIG->externals_priorities[$type])) {
+ $CONFIG->externals_priorities[$type] = array();
+ }
+
+ $CONFIG->externals_priorities[$type][$name] = $priority;
+
+ return true;
+}
+
+function elgg_remove_external_file_priority($name, $type) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->externals_priorities)) {
+ $CONFIG->externals_priorities = array();
}
+
+ if (!isset($CONFIG->externals_priorities[$type])) {
+ $CONFIG->externals_priorities[$type] = array();
+ }
+
+ unset($CONFIG->externals_priorities[$type][$name]);
+
+ return true;
}
/**
@@ -394,13 +457,12 @@ function elgg_load_external_file($type, $name) {
function elgg_get_loaded_external_files($type, $location) {
global $CONFIG;
- if (isset($CONFIG->externals) && isset($CONFIG->externals[$type])) {
- $items = array_values($CONFIG->externals[$type]);
+ if (isset($CONFIG->externals) && $CONFIG->externals[$type] instanceof ElggPriorityList) {
+ $items = $CONFIG->externals[$type]->getElements();
$callback = "return \$v->loaded == true && \$v->location == '$location';";
$items = array_filter($items, create_function('$v', $callback));
if ($items) {
- usort($items, create_function('$a,$b','return $a->priority >= $b->priority;'));
array_walk($items, create_function('&$v,$k', '$v = $v->url;'));
}
return $items;
diff --git a/engine/tests/api/helpers.php b/engine/tests/api/helpers.php
index 461627547..cceb762be 100644
--- a/engine/tests/api/helpers.php
+++ b/engine/tests/api/helpers.php
@@ -31,6 +31,7 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
global $CONFIG;
unset($CONFIG->externals);
+ unset($CONFIG->externals_priorities);
}
/**
@@ -106,7 +107,9 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
// specify name
$result = elgg_register_js('key', 'http://test1.com', 'footer');
$this->assertTrue($result);
- $this->assertIdentical('http://test1.com', $CONFIG->externals['js']['key']->url);
+ $this->assertTrue(isset($CONFIG->externals_priorities['js']['key']));
+ $index = $CONFIG->externals_priorities['js']['key'];
+ $this->assertIdentical('http://test1.com', $CONFIG->externals['js'][$index]->url);
// send a bad url
$result = @elgg_register_js('bad');
@@ -122,7 +125,9 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
// specify name
$result = elgg_register_css('key', 'http://test1.com');
$this->assertTrue($result);
- $this->assertIdentical('http://test1.com', $CONFIG->externals['css']['key']->url);
+ $this->assertTrue(isset($CONFIG->externals_priorities['css']['key']));
+ $index = elgg_get_external_file_priority('css', 'key');
+ $this->assertIdentical('http://test1.com', $CONFIG->externals['css'][$index]->url);
}
/**
@@ -140,7 +145,13 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
$result = elgg_unregister_js('id1');
$this->assertTrue($result);
- @$this->assertNULL($CONFIG->externals['js']['head']['id1']);
+
+ $js = $CONFIG->externals['js'];
+ $elements = $js->getElements();
+ $this->assertFalse(isset($CONFIG->externals_priorities['js']['id1']));
+ foreach ($elements as $element) {
+ $this->assertFalse($element->name == 'id1');
+ }
$result = elgg_unregister_js('id1');
$this->assertFalse($result);
@@ -148,7 +159,15 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
$this->assertFalse($result);
$result = elgg_unregister_js('id2');
- $this->assertIdentical($urls['id3'], $CONFIG->externals['js']['id3']->url);
+ $elements = $js->getElements();
+ $this->assertFalse(isset($CONFIG->externals_priorities['js']['id2']));
+ foreach ($elements as $element) {
+ $this->assertFalse($element->name == 'id2');
+ }
+
+ $this->assertTrue(isset($CONFIG->externals_priorities['js']['id3']));
+ $priority = $CONFIG->externals_priorities['js']['id3'];
+ $this->assertIdentical($urls['id3'], $CONFIG->externals['js'][$priority]->url);
}
/**
@@ -187,4 +206,298 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest {
$js_urls = elgg_get_loaded_js('footer');
$this->assertIdentical(array(), $js_urls);
}
-}
+
+ // test ElggPriorityList
+ public function testElggPriorityListAdd() {
+ $pl = new ElggPriorityList();
+ $elements = array(
+ 'Test value',
+ 'Test value 2',
+ 'Test value 3'
+ );
+
+ shuffle($elements);
+
+ foreach ($elements as $element) {
+ $this->assertTrue($pl->add($element) !== false);
+ }
+
+ $test_elements = $pl->getElements();
+
+ $this->assertTrue(is_array($test_elements));
+
+ foreach ($test_elements as $i => $element) {
+ // should be in the array
+ $this->assertTrue(in_array($element, $elements));
+
+ // should be the only element, so priority 0
+ $this->assertEqual($i, array_search($element, $elements));
+ }
+ }
+
+ public function testElggPriorityListAddWithPriority() {
+ $pl = new ElggPriorityList();
+
+ $elements = array(
+ 10 => 'Test Element 10',
+ 5 => 'Test Element 5',
+ 0 => 'Test Element 0',
+ 100 => 'Test Element 100',
+ -1 => 'Test Element -1',
+ -5 => 'Test Element -5'
+ );
+
+ foreach ($elements as $priority => $element) {
+ $pl->add($element, $priority);
+ }
+
+ $test_elements = $pl->getElements();
+
+ // should be sorted by priority
+ $elements_sorted = array(
+ -5 => 'Test Element -5',
+ -1 => 'Test Element -1',
+ 0 => 'Test Element 0',
+ 5 => 'Test Element 5',
+ 10 => 'Test Element 10',
+ 100 => 'Test Element 100',
+ );
+
+ $this->assertIdentical($elements_sorted, $test_elements);
+
+ foreach ($test_elements as $priority => $element) {
+ $this->assertIdentical($elements[$priority], $element);
+ }
+ }
+
+ public function testElggPriorityListGetNextPriority() {
+ $pl = new ElggPriorityList();
+
+ $elements = array(
+ 2 => 'Test Element',
+ 0 => 'Test Element 2',
+ -2 => 'Test Element 3',
+ );
+
+ foreach ($elements as $priority => $element) {
+ $pl->add($element, $priority);
+ }
+
+ // we're not specifying a priority so it should be the next consecutive to 0.
+ $this->assertEqual(1, $pl->getNextPriority());
+
+ // add another one at priority 1
+ $pl->add('Test Element 1');
+
+ // next consecutive to 0 is now 3.
+ $this->assertEqual(3, $pl->getNextPriority());
+ }
+
+ public function testElggPriorityListRemove() {
+ $pl = new ElggPriorityList();
+
+ $elements = array();
+ for ($i=0; $i<3; $i++) {
+ $element = new stdClass();
+ $element->name = "Test Element $i";
+ $element->someAttribute = rand(0, 9999);
+ $elements[] = $element;
+ $pl->add($element);
+ }
+
+ $pl->remove($elements[1]);
+
+ $test_elements = $pl->getElements();
+
+ // make sure it's gone.
+ $this->assertTrue(2, count($test_elements));
+ $this->assertIdentical($elements[0], $test_elements[0]);
+ $this->assertIdentical($elements[2], $test_elements[2]);
+ }
+
+ public function testElggPriorityListConstructor() {
+ $elements = array(
+ 10 => 'Test Element 10',
+ 5 => 'Test Element 5',
+ 0 => 'Test Element 0',
+ 100 => 'Test Element 100',
+ -1 => 'Test Element -1',
+ -5 => 'Test Element -5'
+ );
+
+ $pl = new ElggPriorityList($elements);
+ $test_elements = $pl->getElements();
+
+ $elements_sorted = array(
+ -5 => 'Test Element -5',
+ -1 => 'Test Element -1',
+ 0 => 'Test Element 0',
+ 5 => 'Test Element 5',
+ 10 => 'Test Element 10',
+ 100 => 'Test Element 100',
+ );
+
+ $this->assertIdentical($elements_sorted, $test_elements);
+ }
+
+ public function testElggPriorityListGetPriority() {
+ $pl = new ElggPriorityList();
+
+ $elements = array(
+ 'Test element 0',
+ 'Test element 1',
+ 'Test element 2',
+ );
+
+ foreach ($elements as $element) {
+ $pl->add($element);
+ }
+
+ $this->assertIdentical(0, $pl->getPriority($elements[0]));
+ $this->assertIdentical(1, $pl->getPriority($elements[1]));
+ $this->assertIdentical(2, $pl->getPriority($elements[2]));
+ }
+
+ public function testElggPriorityListPriorityCollision() {
+ $pl = new ElggPriorityList();
+
+ $elements = array(
+ 5 => 'Test element 5',
+ 6 => 'Test element 6',
+ 0 => 'Test element 0',
+ );
+
+ foreach ($elements as $priority => $element) {
+ $pl->add($element, $priority);
+ }
+
+ // add at a colliding priority
+ $pl->add('Colliding element', 5);
+
+ // should float to the top closest to 5, so 7
+ $this->assertEqual(7, $pl->getPriority('Colliding element'));
+ }
+
+ public function testElggPriorityListArrayAccess() {
+ $pl = new ElggPriorityList();
+
+ $pl[] = 'Test element 0';
+ $pl[-10] = 'Test element -10';
+ $pl[-1] = 'Test element -1';
+ $pl[] = 'Test element 1';
+ $pl[5] = 'Test element 5';
+ $pl[0] = 'Test element collision with 0';
+
+ $elements = array(
+ -1 => 'Test element -1',
+ 0 => 'Test element collision with 0',
+ 1 => 'Test element 0',
+ 2 => 'Test element 1',
+ 5 => 'Test element 5',
+ );
+
+ $priority = $pl->getPriority('Test element -10');
+ unset($pl[$priority]);
+
+ $test_elements = $pl->getElements();
+ $this->assertIdentical($elements, $test_elements);
+ }
+
+ public function testElggPriorityListIterator() {
+ $elements = array(
+ -5 => 'Test element -5',
+ 0 => 'Test element 0',
+ 5 => 'Test element 5'
+ );
+
+ $pl = new ElggPriorityList($elements);
+
+ foreach ($pl as $priority => $element) {
+ $this->assertIdentical($elements[$priority], $element);
+ }
+ }
+
+ public function testElggPriorityListCountable() {
+ $pl = new ElggPriorityList();
+
+ $this->assertEqual(0, count($pl));
+
+ $pl[] = 'Test element 0';
+ $this->assertEqual(1, count($pl));
+
+ $pl[] = 'Test element 1';
+ $this->assertEqual(2, count($pl));
+
+ $pl[] = 'Test element 2';
+ $this->assertEqual(3, count($pl));
+ }
+
+ public function testElggPriorityListUserSort() {
+ $elements = array(
+ 'A',
+ 'B',
+ 'C',
+ 'D',
+ 'E',
+ );
+
+ $elements_sorted_string = $elements;
+
+ shuffle($elements);
+ $pl = new ElggPriorityList($elements);
+
+ // will sort by priority
+ $test_elements = $pl->getElements();
+ $this->assertIdentical($elements, $test_elements);
+
+ function test_sort($elements) {
+ sort($elements, SORT_LOCALE_STRING);
+ return $elements;
+ }
+
+ // force a new sort using our function
+ $pl->sort('test_sort');
+ $test_elements = $pl->getElements();
+
+ $this->assertIdentical($elements_sorted_string, $test_elements);
+ }
+
+ function testElggPriorityListShiftElementsSegment() {
+ $elements = array(
+ 0 => 'Element 0',
+ 1 => 'Element 1',
+ 2 => 'Element 2',
+ 4 => 'Element 4',
+ );
+
+ $pl = new ElggPriorityList($elements);
+
+ // add a new element directly at 1.
+ $pl->add('New Element', 1, true);
+
+ $elements_sorted = array(
+ 0 => 'Element 0',
+ 1 => 'New Element',
+ 2 => 'Element 1',
+ 3 => 'Element 2',
+ 4 => 'Element 4',
+ );
+
+ $test_elements = $pl->getElements();
+ $this->assertIdentical($elements_sorted, $test_elements);
+
+ $pl->add('New Element 10', 10, true);
+
+ $elements_sorted = array(
+ 0 => 'Element 0',
+ 1 => 'New Element',
+ 2 => 'Element 1',
+ 3 => 'Element 2',
+ 4 => 'Element 4',
+ 10 => 'New Element 10'
+ );
+
+ $test_elements = $pl->getElements();
+ $this->assertIdentical($elements_sorted, $test_elements);
+ }
+} \ No newline at end of file