<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.runerealm.org/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AGadget-checkboxList-core.js</id>
	<title>MediaWiki:Gadget-checkboxList-core.js - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.runerealm.org/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AGadget-checkboxList-core.js"/>
	<link rel="alternate" type="text/html" href="https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;action=history"/>
	<updated>2026-04-11T05:09:51Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.41.1</generator>
	<entry>
		<id>https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;diff=42183&amp;oldid=prev</id>
		<title>Alex at 11:06, 20 October 2024</title>
		<link rel="alternate" type="text/html" href="https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;diff=42183&amp;oldid=prev"/>
		<updated>2024-10-20T11:06:07Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;amp;diff=42183&amp;amp;oldid=39028&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>Alex</name></author>
	</entry>
	<entry>
		<id>https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;diff=39028&amp;oldid=prev</id>
		<title>Alex at 16:14, 17 October 2024</title>
		<link rel="alternate" type="text/html" href="https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;diff=39028&amp;oldid=prev"/>
		<updated>2024-10-17T16:14:49Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;amp;diff=39028&amp;amp;oldid=38897&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>Alex</name></author>
	</entry>
	<entry>
		<id>https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;diff=38897&amp;oldid=prev</id>
		<title>Alex at 16:12, 17 October 2024</title>
		<link rel="alternate" type="text/html" href="https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;diff=38897&amp;oldid=prev"/>
		<updated>2024-10-17T16:12:29Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;amp;diff=38897&amp;amp;oldid=34593&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>Alex</name></author>
	</entry>
	<entry>
		<id>https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;diff=34593&amp;oldid=prev</id>
		<title>Alex at 23:10, 16 October 2024</title>
		<link rel="alternate" type="text/html" href="https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;diff=34593&amp;oldid=prev"/>
		<updated>2024-10-16T23:10:04Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 01:10, 17 October 2024&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 280:&lt;/td&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 280:&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;        /*&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;        /*&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         * Merge the updated data for the current page into the data for other pages into local storage.&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         * Merge the updated data for the current page into the data for other &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;mw.&lt;/ins&gt;pages into local storage.&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         *&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         *&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         * @param hashedPageName A hash of the current page name.&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         * @param hashedPageName A hash of the current page name.&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Alex</name></author>
	</entry>
	<entry>
		<id>https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;diff=836&amp;oldid=prev</id>
		<title>Alex: Created page with &quot;/**  * Adds support for checkbox lists (Template:Checklist)  *  * Examples/Tests: &lt;https://rs.wiki/User:Cqm/Scrapbook_4&gt;  *  * History:  * - 1.0: Original implementation - Cqm  */  /*  * DATA STORAGE STRUCTURE  * ----------------------  *  * In its raw, uncompressed format, the stored data is as follows:  * {  *     hashedPageName1: [  *         [0, 1, 0, 1, 0, 1],  *         [1, 0, 1, 0, 1, 0],  *         [0, 0, 0, 0, 0, 0]  *     ],  *     hashedPageName2: [  *...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.runerealm.org/index.php?title=MediaWiki:Gadget-checkboxList-core.js&amp;diff=836&amp;oldid=prev"/>
		<updated>2024-10-13T00:25:56Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;*  * Adds support for checkbox lists (&lt;a href=&quot;/w/Template:Checklist&quot; title=&quot;Template:Checklist&quot;&gt;Template:Checklist&lt;/a&gt;)  *  * Examples/Tests: &amp;lt;https://rs.wiki/User:Cqm/Scrapbook_4&amp;gt;  *  * History:  * - 1.0: Original implementation - Cqm: &lt;/span&gt;  /*  * DATA STORAGE STRUCTURE  * ----------------------  *  * In its raw, uncompressed format, the stored data is as follows:  * {  *     hashedPageName1: [  *         [0, 1, 0, 1, 0, 1],  *         [1, 0, 1, 0, 1, 0],  *         [0, 0, 0, 0, 0, 0]  *     ],  *     hashedPageName2: [  *...&amp;quot;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;/**&lt;br /&gt;
 * Adds support for checkbox lists ([[Template:Checklist]])&lt;br /&gt;
 *&lt;br /&gt;
 * Examples/Tests: &amp;lt;https://rs.wiki/User:Cqm/Scrapbook_4&amp;gt;&lt;br /&gt;
 *&lt;br /&gt;
 * History:&lt;br /&gt;
 * - 1.0: Original implementation - Cqm&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * DATA STORAGE STRUCTURE&lt;br /&gt;
 * ----------------------&lt;br /&gt;
 *&lt;br /&gt;
 * In its raw, uncompressed format, the stored data is as follows:&lt;br /&gt;
 * {&lt;br /&gt;
 *     hashedPageName1: [&lt;br /&gt;
 *         [0, 1, 0, 1, 0, 1],&lt;br /&gt;
 *         [1, 0, 1, 0, 1, 0],&lt;br /&gt;
 *         [0, 0, 0, 0, 0, 0]&lt;br /&gt;
 *     ],&lt;br /&gt;
 *     hashedPageName2: [&lt;br /&gt;
 *         [0, 1, 0, 1, 0, 1],&lt;br /&gt;
 *         [1, 0, 1, 0, 1, 0],&lt;br /&gt;
 *         [0, 0, 0, 0, 0, 0]&lt;br /&gt;
 *     ]&lt;br /&gt;
 * }&lt;br /&gt;
 *&lt;br /&gt;
 * Where `hashedPageNameX` is the value of wgPageName passed through our `hashString` function,&lt;br /&gt;
 * the arrays of numbers representing tables on a page (from top to bottom) and the numbers&lt;br /&gt;
 * representing whether a row is highlighted or not, depending on if it is 1 or 0 respectively.&lt;br /&gt;
 *&lt;br /&gt;
 * During compression, these numbers are collected into groups of 6 and converted to base64.&lt;br /&gt;
 * For example:&lt;br /&gt;
 *&lt;br /&gt;
 *   1. [0, 1, 0, 1, 0, 1]&lt;br /&gt;
 *   2. 0x010101             (1 + 4 + 16 = 21)&lt;br /&gt;
 *   3. BASE_64_URL[21]      (U)&lt;br /&gt;
 *&lt;br /&gt;
 * Once each table&amp;#039;s rows have been compressed into strings, they are concatenated using `.` as a&lt;br /&gt;
 * delimiter. The hashed page name (which is guaranteed to be 8 characters long) is then prepended&lt;br /&gt;
 * to this string to look something like the following:&lt;br /&gt;
 *&lt;br /&gt;
 *   XXXXXXXXab.dc.ef&lt;br /&gt;
 *&lt;br /&gt;
 *&lt;br /&gt;
 * The first character of a hashed page name is then used to form the object that is actually&lt;br /&gt;
 * stored. As the hashing function uses hexadecimal, this gives us 16 possible characters (0-9A-Z).&lt;br /&gt;
 *&lt;br /&gt;
 * {&lt;br /&gt;
 *     A: ...&lt;br /&gt;
 *     B: ...&lt;br /&gt;
 *     C: ...&lt;br /&gt;
 *     // etc.&lt;br /&gt;
 * }&lt;br /&gt;
 *&lt;br /&gt;
 * The final step of compression is to merge each page&amp;#039;s data together under it&amp;#039;s respective top&lt;br /&gt;
 * level key. this is done by concatenation again, separated by a `!`.&lt;br /&gt;
 *&lt;br /&gt;
 * The resulting object is then converted to a string and persisted in local storage. When&lt;br /&gt;
 * uncompressing data, simply perform the following steps in reverse.&lt;br /&gt;
 *&lt;br /&gt;
 * For the implementation of this algorithm, see:&lt;br /&gt;
 * - `compress`&lt;br /&gt;
 * - `parse`&lt;br /&gt;
 * - `hashString`&lt;br /&gt;
 *&lt;br /&gt;
 * Note that while rows could theoretically be compressed further by using all ASCII characters,&lt;br /&gt;
 * eventually we&amp;#039;d start using characters outside printable ASCII which makes debugging painful.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
/*jshint bitwise:false, camelcase:true, curly:true, eqeqeq:true, es3:false,&lt;br /&gt;
    forin:true, immed:true, indent:4, latedef:true, newcap:true,&lt;br /&gt;
    noarg:true, noempty:true, nonew:true, plusplus:true, quotmark:single,&lt;br /&gt;
    undef:true, unused:true, strict:true, trailing:true,&lt;br /&gt;
    browser:true, devel:false, jquery:true,&lt;br /&gt;
    onevar:true&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
&amp;#039;use strict&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
    // constants&lt;br /&gt;
var STORAGE_KEY = &amp;#039;rs:checkList&amp;#039;,&lt;br /&gt;
    LIST_CLASS = &amp;#039;checklist&amp;#039;,&lt;br /&gt;
    CHECKED_CLASS = &amp;#039;checked&amp;#039;,&lt;br /&gt;
    NO_TOGGLE_PARENT_CLASS = &amp;#039;no-toggle-parent&amp;#039;,&lt;br /&gt;
    INDEX_ATTRIBUTE = &amp;#039;data-checklist-index&amp;#039;,&lt;br /&gt;
    BASE_64_URL = &amp;#039;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_&amp;#039;,&lt;br /&gt;
    PAGE_SEPARATOR = &amp;#039;!&amp;#039;,&lt;br /&gt;
    LIST_SEPARATOR = &amp;#039;.&amp;#039;,&lt;br /&gt;
    CASTAGNOLI_POLYNOMIAL = 0x04c11db7,&lt;br /&gt;
    UINT32_MAX = 0xffffffff,&lt;br /&gt;
&lt;br /&gt;
    conf = mw.config.get([&lt;br /&gt;
        &amp;#039;debug&amp;#039;,&lt;br /&gt;
        &amp;#039;wgPageName&amp;#039;&lt;br /&gt;
    ]),&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    self = {&lt;br /&gt;
        /*&lt;br /&gt;
         * Stores the current uncompressed data for the current page.&lt;br /&gt;
         */&lt;br /&gt;
        data: null,&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * Perform initial checks on the page and browser.&lt;br /&gt;
         */&lt;br /&gt;
        init: function () {&lt;br /&gt;
            var $lists = $([&amp;#039;ul.&amp;#039; + LIST_CLASS,&lt;br /&gt;
                            &amp;#039;div.&amp;#039; + LIST_CLASS + &amp;#039; &amp;gt; ul&amp;#039;].join(&amp;#039;, &amp;#039;)),&lt;br /&gt;
                hashedPageName = self.hashString(mw.config.get(&amp;#039;wgPageName&amp;#039;));&lt;br /&gt;
&lt;br /&gt;
            // check we have some tables to interact with&lt;br /&gt;
            if (!$lists.length) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // check the browser supports local storage&lt;br /&gt;
            if (!rs.hasLocalStorage()) {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            self.data = self.load(hashedPageName, $lists.length);&lt;br /&gt;
            self.initLists(hashedPageName, $lists);&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * Initialise table highlighting.&lt;br /&gt;
         *&lt;br /&gt;
         * @param hashedPageName The current page name as a hash.&lt;br /&gt;
         * @param $lists A list of checkbox lists on the current page.&lt;br /&gt;
         */&lt;br /&gt;
        initLists: function (hashedPageName, $lists) {&lt;br /&gt;
            $lists.each(function (listIndex) {&lt;br /&gt;
                var $this = $(this),&lt;br /&gt;
                    toggleParent = !(&lt;br /&gt;
                        $this.hasClass(NO_TOGGLE_PARENT_CLASS) ||&lt;br /&gt;
                        $this.parent(&amp;#039;div.&amp;#039; + LIST_CLASS).hasClass(NO_TOGGLE_PARENT_CLASS)&lt;br /&gt;
                    ),&lt;br /&gt;
                    // list items&lt;br /&gt;
                    $items = $this.find(&amp;#039;li&amp;#039;),&lt;br /&gt;
                    listData = self.data[listIndex];&lt;br /&gt;
&lt;br /&gt;
                // initialise list items if necessary&lt;br /&gt;
                while ($items.length &amp;gt; listData.length) {&lt;br /&gt;
                    listData.push(0);&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $items.each(function (itemIndex) {&lt;br /&gt;
                    var $this = $(this),&lt;br /&gt;
                        itemData = listData[itemIndex];&lt;br /&gt;
&lt;br /&gt;
                    // initialize checking based on the cookie&lt;br /&gt;
                    self.setChecked($this, itemData);&lt;br /&gt;
&lt;br /&gt;
                    // give the item a unique index in the list&lt;br /&gt;
                    $this.attr(INDEX_ATTRIBUTE, itemIndex);&lt;br /&gt;
&lt;br /&gt;
                    // set mouse events&lt;br /&gt;
                    $this&lt;br /&gt;
                        .click(function (e) {&lt;br /&gt;
                            var $this = $(this),&lt;br /&gt;
                                $parent = $this.parent(&amp;#039;ul&amp;#039;).parent(&amp;#039;li&amp;#039;),&lt;br /&gt;
                                $childItems = $this.children(&amp;#039;ul&amp;#039;).children(&amp;#039;li&amp;#039;),&lt;br /&gt;
                                isChecked;&lt;br /&gt;
&lt;br /&gt;
                            // don&amp;#039;t bubble up to parent lists&lt;br /&gt;
                            e.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
                            function checkChildItems() {&lt;br /&gt;
                                var $this = $(this),&lt;br /&gt;
                                    index = $this.attr(INDEX_ATTRIBUTE),&lt;br /&gt;
                                    $childItems = $this.children(&amp;#039;ul&amp;#039;).children(&amp;#039;li&amp;#039;),&lt;br /&gt;
                                    childIsChecked = $this.hasClass(CHECKED_CLASS);&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    (isChecked &amp;amp;&amp;amp; !childIsChecked) ||&lt;br /&gt;
                                    (!isChecked &amp;amp;&amp;amp; childIsChecked)&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    listData[index] = 1 - listData[index];&lt;br /&gt;
                                    self.setChecked($this, listData[index]);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                if ($childItems.length) {&lt;br /&gt;
                                    $childItems.each(checkChildItems);&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            function checkParent($parent) {&lt;br /&gt;
                                var parentIndex = $parent.attr(INDEX_ATTRIBUTE),&lt;br /&gt;
                                    parentIsChecked = $parent.hasClass(CHECKED_CLASS),&lt;br /&gt;
                                    parentShouldBeChecked = true,&lt;br /&gt;
                                    $myParent = $parent.parent(&amp;#039;ul&amp;#039;).parent(&amp;#039;li&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
                                $parent.children(&amp;#039;ul&amp;#039;).children(&amp;#039;li&amp;#039;).each(function () {&lt;br /&gt;
                                    var $child = $(this),&lt;br /&gt;
                                        childIsChecked = $child.hasClass(CHECKED_CLASS);&lt;br /&gt;
&lt;br /&gt;
                                    if (!childIsChecked) {&lt;br /&gt;
                                        parentShouldBeChecked = false;&lt;br /&gt;
                                    }&lt;br /&gt;
                                });&lt;br /&gt;
&lt;br /&gt;
                                if (&lt;br /&gt;
                                    (parentShouldBeChecked &amp;amp;&amp;amp; !parentIsChecked &amp;amp;&amp;amp; toggleParent) ||&lt;br /&gt;
                                    (!parentShouldBeChecked &amp;amp;&amp;amp; parentIsChecked)&lt;br /&gt;
                                ) {&lt;br /&gt;
                                    listData[parentIndex] = 1 - listData[parentIndex];&lt;br /&gt;
                                    self.setChecked($parent, listData[parentIndex]);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                if ($myParent.length) {&lt;br /&gt;
                                    checkParent($myParent);&lt;br /&gt;
                                }&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            // don&amp;#039;t toggle highlight when clicking links&lt;br /&gt;
                            if ((e.target.tagName !== &amp;#039;A&amp;#039;) &amp;amp;&amp;amp; (e.target.tagName !== &amp;#039;IMG&amp;#039;)) {&lt;br /&gt;
                                // 1 -&amp;gt; 0&lt;br /&gt;
                                // 0 -&amp;gt; 1&lt;br /&gt;
                                listData[itemIndex] = 1 - listData[itemIndex];&lt;br /&gt;
&lt;br /&gt;
                                self.setChecked($this, listData[itemIndex]);&lt;br /&gt;
                                isChecked = $this.hasClass(CHECKED_CLASS);&lt;br /&gt;
&lt;br /&gt;
                                if ($childItems.length) {&lt;br /&gt;
                                    $childItems.each(checkChildItems);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                // if the list has a parent&lt;br /&gt;
                                // check if all the children are checked and uncheck the parent if not&lt;br /&gt;
                                if ($parent.length) {&lt;br /&gt;
                                    checkParent($parent);&lt;br /&gt;
                                }&lt;br /&gt;
&lt;br /&gt;
                                self.save(hashedPageName);&lt;br /&gt;
                            }&lt;br /&gt;
                        });&lt;br /&gt;
                });&lt;br /&gt;
                &lt;br /&gt;
                // add a button for reset&lt;br /&gt;
                var reset = $(&amp;#039;&amp;lt;div&amp;gt;&amp;#039;).append(&lt;br /&gt;
                	$(&amp;#039;&amp;lt;sup&amp;gt;&amp;#039;).append(&amp;#039;[&amp;#039;).append(&lt;br /&gt;
                		$(&amp;#039;&amp;lt;a&amp;gt;&amp;#039;).append(&amp;#039;uncheck all&amp;#039;)&lt;br /&gt;
            		).append(&amp;#039;]&amp;#039;)&lt;br /&gt;
                ).addClass(&amp;#039;sl-reset&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
                reset.first(&amp;#039;sup&amp;#039;).click(function () {&lt;br /&gt;
                    $items.each(function (itemIndex) {&lt;br /&gt;
                        listData[itemIndex] = 0;&lt;br /&gt;
                        self.setChecked($(this), 0);&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    self.save(hashedPageName, $lists.length);&lt;br /&gt;
                });&lt;br /&gt;
                &lt;br /&gt;
                $this.append(reset);&lt;br /&gt;
            });&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * Change the list item checkbox based on mouse events.&lt;br /&gt;
         *&lt;br /&gt;
         * @param $item The list item element.&lt;br /&gt;
         * @param val The value to control what class to add (if any).&lt;br /&gt;
         *            0 -&amp;gt; unchecked (no class)&lt;br /&gt;
         *            1 -&amp;gt; light on&lt;br /&gt;
         *            2 -&amp;gt; mouse over&lt;br /&gt;
         */&lt;br /&gt;
        setChecked: function ($item, val) {&lt;br /&gt;
            $item.removeClass(CHECKED_CLASS);&lt;br /&gt;
&lt;br /&gt;
            switch (val) {&lt;br /&gt;
                // checked&lt;br /&gt;
                case 1:&lt;br /&gt;
                    $item.addClass(CHECKED_CLASS);&lt;br /&gt;
                    break;&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * Merge the updated data for the current page into the data for other pages into local storage.&lt;br /&gt;
         *&lt;br /&gt;
         * @param hashedPageName A hash of the current page name.&lt;br /&gt;
         */&lt;br /&gt;
        save: function (hashedPageName) {&lt;br /&gt;
                // load the existing data so we know where to save it&lt;br /&gt;
            var curData = localStorage.getItem(STORAGE_KEY),&lt;br /&gt;
                compressedData;&lt;br /&gt;
&lt;br /&gt;
            if (curData === null) {&lt;br /&gt;
                curData = {};&lt;br /&gt;
            } else {&lt;br /&gt;
                curData = JSON.parse(curData);&lt;br /&gt;
                curData = self.parse(curData);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // merge in our updated data and compress it&lt;br /&gt;
            curData[hashedPageName] = self.data;&lt;br /&gt;
            compressedData = self.compress(curData);&lt;br /&gt;
&lt;br /&gt;
            // convert to a string and save to localStorage&lt;br /&gt;
            compressedData = JSON.stringify(compressedData);&lt;br /&gt;
            localStorage.setItem(STORAGE_KEY, compressedData);&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * Compress the entire data set using tha algoritm documented at the top of the page.&lt;br /&gt;
         *&lt;br /&gt;
         * @param data The data to compress.&lt;br /&gt;
         *&lt;br /&gt;
         * @return the compressed data.&lt;br /&gt;
         */&lt;br /&gt;
        compress: function (data) {&lt;br /&gt;
            var ret = {};&lt;br /&gt;
            &lt;br /&gt;
            Object.keys(data).forEach(function (hashedPageName) {&lt;br /&gt;
                var pageData = data[hashedPageName],&lt;br /&gt;
                    pageKey = hashedPageName.charAt(0);&lt;br /&gt;
&lt;br /&gt;
                if (!ret.hasOwnProperty(pageKey)) {&lt;br /&gt;
                    ret[pageKey] = {};&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                ret[pageKey][hashedPageName] = [];&lt;br /&gt;
&lt;br /&gt;
                pageData.forEach(function (tableData) {&lt;br /&gt;
                    var compressedListData = &amp;#039;&amp;#039;,&lt;br /&gt;
                        i, j, k;&lt;br /&gt;
&lt;br /&gt;
                    for (i = 0; i &amp;lt; Math.ceil(tableData.length / 6); i += 1) {&lt;br /&gt;
                        k = tableData[6 * i];&lt;br /&gt;
&lt;br /&gt;
                        for (j = 1; j &amp;lt; 6; j += 1) {&lt;br /&gt;
                            k = 2 * k + ((6 * i + j &amp;lt; tableData.length) ? tableData[6 * i + j] : 0);&lt;br /&gt;
                        }&lt;br /&gt;
&lt;br /&gt;
                        compressedListData += BASE_64_URL.charAt(k);&lt;br /&gt;
                    }&lt;br /&gt;
&lt;br /&gt;
                    ret[pageKey][hashedPageName].push(compressedListData);&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                ret[pageKey][hashedPageName] = ret[pageKey][hashedPageName].join(LIST_SEPARATOR);&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            Object.keys(ret).forEach(function (pageKey) {&lt;br /&gt;
                var hashKeys = Object.keys(ret[pageKey]),&lt;br /&gt;
                    hashedData = [];&lt;br /&gt;
&lt;br /&gt;
                hashKeys.forEach(function (key) {&lt;br /&gt;
                    var pageData = ret[pageKey][key];&lt;br /&gt;
                    hashedData.push(key + pageData);&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                hashedData = hashedData.join(PAGE_SEPARATOR);&lt;br /&gt;
                ret[pageKey] = hashedData;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            return ret;&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * Get the existing data for the current page.&lt;br /&gt;
         *&lt;br /&gt;
         * @param hashedPageName A hash of the current page name.&lt;br /&gt;
         * @param numLists The number of lists on the current page. Used to ensure the loaded&lt;br /&gt;
         *                 data matches the number of lists on the page thus handling cases&lt;br /&gt;
         *                 where lists have been added or removed. This does not check the&lt;br /&gt;
         *                 amount of items in the given lists.&lt;br /&gt;
         *&lt;br /&gt;
         * @return The data for the current page.&lt;br /&gt;
         */&lt;br /&gt;
        load: function (hashedPageName, numLists) {&lt;br /&gt;
            var data = localStorage.getItem(STORAGE_KEY),&lt;br /&gt;
                pageData;&lt;br /&gt;
&lt;br /&gt;
            if (data === null) {&lt;br /&gt;
                pageData = [];&lt;br /&gt;
            } else {&lt;br /&gt;
                data = JSON.parse(data);&lt;br /&gt;
                data = self.parse(data);&lt;br /&gt;
&lt;br /&gt;
                if (data.hasOwnProperty(hashedPageName)) {&lt;br /&gt;
                    pageData = data[hashedPageName];&lt;br /&gt;
                } else {&lt;br /&gt;
                    pageData = [];&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // if more lists were added&lt;br /&gt;
            // add extra arrays to store the data in&lt;br /&gt;
            // also populates if no existing data was found&lt;br /&gt;
            while (numLists &amp;gt; pageData.length) {&lt;br /&gt;
                pageData.push([]);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // if lists were removed, remove data from the end of the list&lt;br /&gt;
            // as there&amp;#039;s no way to tell which was removed&lt;br /&gt;
            while (numLists &amp;lt; pageData.length) {&lt;br /&gt;
                pageData.pop();&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return pageData;&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * Parse the compressed data as loaded from local storage using the algorithm desribed&lt;br /&gt;
         * at the top of the page.&lt;br /&gt;
         *&lt;br /&gt;
         * @param data The data to parse.&lt;br /&gt;
         *&lt;br /&gt;
         * @return the parsed data.&lt;br /&gt;
         */&lt;br /&gt;
        parse: function (data) {&lt;br /&gt;
            var ret = {};&lt;br /&gt;
&lt;br /&gt;
            Object.keys(data).forEach(function (pageKey) {&lt;br /&gt;
                var pageData = data[pageKey].split(PAGE_SEPARATOR);&lt;br /&gt;
&lt;br /&gt;
                pageData.forEach(function (listData) {&lt;br /&gt;
                    var hashedPageName = listData.substr(0, 8);&lt;br /&gt;
&lt;br /&gt;
                    listData = listData.substr(8).split(LIST_SEPARATOR);&lt;br /&gt;
                    ret[hashedPageName] = [];&lt;br /&gt;
&lt;br /&gt;
                    listData.forEach(function (itemData, index) {&lt;br /&gt;
                        var i, j, k;&lt;br /&gt;
&lt;br /&gt;
                        ret[hashedPageName].push([]);&lt;br /&gt;
&lt;br /&gt;
                        for (i = 0; i &amp;lt; itemData.length; i += 1) {&lt;br /&gt;
                            k = BASE_64_URL.indexOf(itemData.charAt(i));&lt;br /&gt;
&lt;br /&gt;
                            // input validation&lt;br /&gt;
                            if (k &amp;lt; 0) {&lt;br /&gt;
                                k = 0;&lt;br /&gt;
                            }&lt;br /&gt;
&lt;br /&gt;
                            for (j = 5; j &amp;gt;= 0; j -= 1) {&lt;br /&gt;
                                ret[hashedPageName][index][6 * i + j] = (k &amp;amp; 0x1);&lt;br /&gt;
                                k &amp;gt;&amp;gt;= 1;&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    });&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            return ret;&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        /*&lt;br /&gt;
         * Hash a string into a big endian 32 bit hex string. Used to hash page names.&lt;br /&gt;
         *&lt;br /&gt;
         * @param input The string to hash.&lt;br /&gt;
         *&lt;br /&gt;
         * @return the result of the hash.&lt;br /&gt;
         */&lt;br /&gt;
        hashString: function (input) {&lt;br /&gt;
            var ret = 0,&lt;br /&gt;
                table = [],&lt;br /&gt;
                i, j, k;&lt;br /&gt;
&lt;br /&gt;
            // guarantee 8-bit chars&lt;br /&gt;
            input = window.unescape(window.encodeURI(input));&lt;br /&gt;
&lt;br /&gt;
            // calculate the crc (cyclic redundancy check) for all 8-bit data&lt;br /&gt;
            // bit-wise operations discard anything left of bit 31&lt;br /&gt;
            for (i = 0; i &amp;lt; 256; i += 1) {&lt;br /&gt;
                k = (i &amp;lt;&amp;lt; 24);&lt;br /&gt;
&lt;br /&gt;
                for (j = 0; j &amp;lt; 8; j += 1) {&lt;br /&gt;
                    k = (k &amp;lt;&amp;lt; 1) ^ ((k &amp;gt;&amp;gt;&amp;gt; 31) * CASTAGNOLI_POLYNOMIAL);&lt;br /&gt;
                }&lt;br /&gt;
                table[i] = k;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // the actual calculation&lt;br /&gt;
            for (i = 0; i &amp;lt; input.length; i += 1) {&lt;br /&gt;
                ret = (ret &amp;lt;&amp;lt; 8) ^ table[(ret &amp;gt;&amp;gt;&amp;gt; 24) ^ input.charCodeAt(i)];&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // make negative numbers unsigned&lt;br /&gt;
            if (ret &amp;lt; 0) {&lt;br /&gt;
                ret += UINT32_MAX;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // 32-bit hex string, padded on the left&lt;br /&gt;
            ret = &amp;#039;0000000&amp;#039; + ret.toString(16).toUpperCase();&lt;br /&gt;
            ret = ret.substr(ret.length - 8);&lt;br /&gt;
&lt;br /&gt;
            return ret;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
// disable for debugging&lt;br /&gt;
if (!([&amp;#039;User:Cqm/Scrapbook_4&amp;#039;].indexOf(conf.wgPageName) &amp;amp;&amp;amp; conf.debug)) {&lt;br /&gt;
    $(self.init);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
// sample data for testing the algorithm used&lt;br /&gt;
var data = {&lt;br /&gt;
    // page1&lt;br /&gt;
    &amp;#039;0FF47C63&amp;#039;: [&lt;br /&gt;
        [0, 1, 1, 0, 1, 0],&lt;br /&gt;
        [0, 1, 1, 0, 1, 0, 1, 1, 1],&lt;br /&gt;
        [0, 0, 0, 0, 1, 1, 0, 0]&lt;br /&gt;
    ],&lt;br /&gt;
    // page2&lt;br /&gt;
    &amp;#039;02B75ABA&amp;#039;: [&lt;br /&gt;
        [0, 1, 0, 1, 1, 0],&lt;br /&gt;
        [1, 1, 1, 0, 1, 0, 1, 1, 0],&lt;br /&gt;
        [0, 0, 1, 1, 0, 0, 0, 0]&lt;br /&gt;
    ],&lt;br /&gt;
    // page3&lt;br /&gt;
    &amp;#039;0676470D&amp;#039;: [&lt;br /&gt;
        [1, 0, 0, 1, 0, 1],&lt;br /&gt;
        [1, 0, 0, 1, 0, 1, 0, 0, 0],&lt;br /&gt;
        [1, 1, 1, 1, 0, 0, 1, 1]&lt;br /&gt;
    ]&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
console.log(&amp;#039;input&amp;#039;, data);&lt;br /&gt;
&lt;br /&gt;
var compressedData = self.compress(data);&lt;br /&gt;
console.log(&amp;#039;compressed&amp;#039;, compressedData);&lt;br /&gt;
&lt;br /&gt;
var parsedData = self.parse(compressedData);&lt;br /&gt;
console.log(parsedData);&lt;br /&gt;
*/&lt;/div&gt;</summary>
		<author><name>Alex</name></author>
	</entry>
</feed>