Mark: Add mark widget. Fixes #1243

This commit is contained in:
Rob Garrison 2016-07-27 18:51:55 -05:00
parent 04287900d3
commit 04f23cebb5
No known key found for this signature in database
GPG Key ID: 0A42D160D71978E1
3 changed files with 557 additions and 0 deletions

View File

@ -0,0 +1,421 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jQuery tablesorter 2.0 - Mark Widget</title>
<!-- jQuery -->
<script src="js/jquery-latest.min.js"></script>
<!-- Demo stuff -->
<link class="ui-theme" rel="stylesheet" href="css/jquery-ui.min.css">
<script src="js/jquery-ui.min.js"></script>
<link rel="stylesheet" href="css/jq.css">
<link href="css/prettify.css" rel="stylesheet">
<script src="js/prettify.js"></script>
<script src="js/docs.js"></script>
<!-- Tablesorter: required -->
<link rel="stylesheet" href="../css/theme.blue.css">
<style id="css">/* Example showing how to change the mark color by column */
tr td:nth-child(1) mark { background: #aa0000; color: #fff; }
tr td:nth-child(2) mark { background: #00aa00; color: #fff; }
tr td:nth-child(3) mark { background: #0000aa; color: #fff; }
tr td:nth-child(4) mark { background: #aaaa00; color: #fff; }
tr td:nth-child(5) mark { background: #00aaaa; color: #fff; }
tr td:nth-child(6) mark { background: #aa00aa; color: #fff; }
</style>
<script src="../js/jquery.tablesorter.js"></script>
<script src="../js/widgets/widget-filter.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mark.js/7.0.2/jquery.mark.js"></script>
<script src="../js/widgets/widget-mark.js"></script>
<script id="js">$(function() {
// ==============================
// WITH filter widget
// ==============================
var $table = $('#table').tablesorter({
theme: 'blue',
widthFixed : true,
// sort & filter diacritics
sortLocaleCompare: true,
widgets: ['zebra', 'filter', 'mark'],
widgetOptions : {
filter_external : 'input[name="keyword"]',
filter_reset : 'button.reset',
// default settings
mark_accuracy: 'partially',
mark_className: '',
mark_debug: false,
mark_diacritics: true,
mark_element: 'mark',
mark_exclude: [],
mark_iframes: false,
mark_log: console,
mark_separateWordSearch: true,
mark_synonyms: {},
// callback functions
mark_done: function(totalMatches) {},
mark_each: function(element) {},
mark_filter: function(node, term, counter, totalCounter) { return true; },
mark_noMatch: function(keyword) {}
}
});
// preset searches for the first table
$('button[data-filter-column]').click(function(){
var filters = [],
$t = $(this),
col = $t.data('filter-column'), // zero-based index, or "all" column
txt = $t.data('filter-text') || $t.text(); // text to add to filter
filters[col === "all" ? $table[0].config.columns : col] = txt;
$.tablesorter.setFilters( $table, filters );
return false;
});
// ==============================
// NO filter widget
// ==============================
var $table2 = $('#table2').tablesorter({
theme: 'blue',
widthFixed : true,
// sort & filter diacritics
sortLocaleCompare: true,
widgets: ['zebra', 'mark'],
widgetOptions : {
// default settings
mark_accuracy: 'partially',
mark_className: '',
mark_debug: false,
mark_diacritics: true,
mark_element: 'mark',
mark_exclude: [],
mark_iframes: false,
mark_log: console,
mark_separateWordSearch: true,
mark_synonyms: {},
// callback functions
mark_done: function(totalMatches) {},
mark_each: function(element) {},
mark_filter: function(node, term, counter, totalCounter) { return true; },
mark_noMatch: function(keyword) {}
}
});
// preset searches on the second table
$('button.table2').click(function(){
// check for reset
var query = $(this).hasClass('reset2') ? '' : this.textContent;
$('#table2-search')
.val(query)
.trigger('input');
});
$('#table2-search').on('input', function() {
var config = $table2[0].config,
filters = [];
// still target the "any" match column
filters[config.columns] = this.value;
// trigger a mark update
$table2.trigger('markUpdate', [filters]);
// or call the function directly
// $.tablesorter.mark.update(config, filters);
});
});</script>
</head>
<body>
<div id="banner">
<h1>table<em>sorter</em></h1>
<h2>Mark Widget</h2>
<h3>Flexible client-side table sorting</h3>
<a href="index.html">Back to documentation</a>
</div>
<div id="main">
<p></p>
<br>
<div id="root" class="accordion">
<h3 id="notes"><a href="#">Notes</a></h3>
<div>
<ul>
<li>Added <span class="verison">v2.27.0</span> for use with the <a href="https://markjs.io/">mark.js</a> plugin.</li>
<li>Notable Issues:
<ul>
<li><button class="bad" type="button" data-filter-column="all">~ae</button> - Some rows won't be highlighted because the filter finds fuzzy matches across rows, while the mark widget is targeting separate cell content.</li>
<li><button type="button" data-filter-column="all">/(aaron|bruce)/i</button> - Using a regular expression search will not include diacritics; use an " OR " search instead <button type="button" data-filter-column="all">aaron|bruce</button>.<br>
I may fix this in future updates.
</li>
<li><button class="bad" type="button" data-filter-column="all">/.*/</button> or <button class="bad" type="button" data-filter-column="all">/(|)/</button> - When a regular expression matches everything, the regex is ignored by the mark widget otherwise, <a href="https://github.com/julmot/mark.js/issues/55">mark.js does bad things</a>; but this regex is okay: <button type="button" data-filter-column="all">/.+/</button>.</li>
<li><button class="bad" type="button" data-filter-column="3"><=22</button> or <button class="bad" type="button" data-filter-column="5">10 - 20</button> - Operators &amp; ranges are not fully supported (these are not supported at all by the filter widget in an "all" columns match - see the documentation on <a href="example-widget-filter-any-match.html#limitations">any match limitations</a>).</li>
<li><button class="bad" type="button" data-filter-column="all">!aaron</button> - There is nothing to highlight for not matches.</li>
</ul>
</li>
<li>The <a href="https://markjs.io/#mark"><code>mark</code> function</a> is used for the following filter queries:
<ul>
<li>Plain text</li>
<li>Logical AND (<code>&nbsp;and&nbsp;</code> or <code>&nbsp;&&&nbsp;</code>) &amp; logical OR (<code>&nbsp;or&nbsp;</code> or <code>|</code>) searches.</li>
<li>Invalid regex (e.g. <code>/(|)/</code>).</li>
<li>Operator, range, exact and not searches.</li>
</ul>
</li>
<li>The <a href="https://markjs.io/#markregexp"><code>markRegExp</code> function</a> is used when the filter contains:
<ul>
<li>A "valid" regular expression</li>
<li>Fuzzy search (<code>~</code>)</li>
<li>Wild card <code>?</code> or <code>*</code> search</li>
</ul>
</li>
<li>Try out the <a href="http://jsfiddle.net/Mottie/odyfw8Lj/">jSFiddle Playground</a>.</li>
</ul>
</div>
<h3><a href="#">Options</a></h3>
<div>
<h4>Mark widget defaults (added inside of tablesorter <code>widgetOptions</code>)</h4>
<h5>The widgetOptions are essentially Mark.js settings with a <code>mark_</code> prefix. All options are dynamically updated.</h5>
<div>
<span class="label label-info">TIP!</span> Click on the link in the function column to reveal full details (or <a href="#" class="toggleAll">toggle</a>|<a href="#" class="showAll">show</a>|<a href="#" class="hideAll">hide</a> all) or double click to update the browser location.
</div>
<table class="options tablesorter-blue" data-sortlist="[[0,0]]">
<thead>
<tr><th>Option</th><th>Default</th><th class="sorter-false">Description</th></tr>
</thead>
<tbody>
<tr id="mark-tsupdateclass">
<td><a href="#" class="permalink">mark_tsUpdate</a></td>
<td>"markUpdate"</td>
<td>This option sets the event that can be triggered on the table to update the marks.
<div class="collapsible">
<br>
Use it as follows:
<pre class="prettyprint lang-js">$('table').tablesorter({
widgets: ['mark'],
widgetOptions: {
mark_tsUpdate: 'markFu'
}
});
$('button.update').click(function(){
// update the marks in the table
$('table').trigger('markFu');
});</pre>
</div>
</td>
</tr>
</tbody>
<tbody class="tablesorter-infoOnly">
<tr>
<th colspan="3">Mark.js settings - see <a href="https://markjs.io/#api">official documentation</a></th>
</tr>
</tbody>
<tbody>
<tr id="mark-element">
<td><span class="permalink">mark_element</span></td>
<td>"mark"</td>
<td>HTML element to wrap matches.</td>
</tr>
<tr id="mark-classname">
<td><span class="permalink">mark_className</span></td>
<td>""</td>
<td>A class name added to the element.</td>
</tr>
<tr id="mark-exclude">
<td><span class="permalink">mark_exclude</span></td>
<td>[]</td>
<td>An array with exclusion selectors. Matches inside these elements will be ignored.</td>
</tr>
<tr id="mark-separatewordsearch">
<td><span class="permalink">mark_separateWordSearch</span></td>
<td>true</td>
<td>Whether to search for each word separated by a blank.</td>
</tr>
<tr id="mark-accuracy">
<td><span class="permalink">mark_accuracy</span></td>
<td>"partially"</td>
<td>Use "partially", "complementary", "exactly" or object - see markjs docs for details.</td>
</tr>
<tr id="mark-diacritics">
<td><span class="permalink">mark_diacritics</span></td>
<td>true</td>
<td>If <code>true</code>, diacritic characters should be matched.</td>
</tr>
<tr id="mark-synonyms">
<td><span class="permalink">mark_synonyms</span></td>
<td>{}</td>
<td>An object with synonyms..</td>
</tr>
<tr id="mark-iframes">
<td><span class="permalink">mark_iframes</span></td>
<td>false</td>
<td>Whether to search also inside iframes.</td>
</tr>
<tr id="mark-each">
<td><span class="permalink">mark_each</span></td>
<td>function(element){}</td>
<td>A callback for each marked element.</td>
</tr>
<tr id="mark-filter">
<td><a href="#" class="permalink">mark_filter</a></td>
<td>function(parameters){ return true; }</td>
<td>A callback to filter or limit matches.
<div class="collapsible">
<br>
When the <code>mark</code> function is called, the function parameters are:
<pre class="prettyprint lang-js">function(node, keyword, matches, totalMatches) { return true; }</pre>
When the <code>markRegExp</code> function is called, the function parameters are:
<pre class="prettyprint lang-js">function(node, match, totalMatches) { return true; }</pre>
<p>In both cases, a <code>return true</code> is needed to highlight the match.</p>
<span class="label label-info">Note</span> See the notes section above to know when which function is called.
</div>
</td>
</tr>
<tr id="mark-nomatch">
<td><a href="#" class="permalink">mark_noMatch</a></td>
<td>function(keyword){}</td>
<td>A callback function that will be called when there are no matches.
<div class="collapsible">
<br>
When the <code>mark</code> function is called, the keyword parameter is a string.
<p>When the <code>markRegExp</code> function is called, the keyword parameter is the regular expression.</p>
<span class="label label-info">Note</span> See the notes section above to know when which function is called.
</div>
</td>
</tr>
<tr id="mark-done">
<td><span class="permalink">mark_done</span></td>
<td>function(totalMatches){}</td>
<td>A callback function after all marks are done.</td>
</tr>
<tr id="mark-debug">
<td><span class="permalink">mark_debug</span></td>
<td>false</td>
<td>If <code>true</code>, messages will be logged.</td>
</tr>
<tr id="mark-log">
<td><span class="permalink">mark_log</span></td>
<td>console</td>
<td>Log message to this object.</td>
</tr>
</tbody>
</table>
</div>
</div>
<p></p>
<h1>Demo: With the Filter Widget</h1>
<br>
Search/Highlight all columns: <input type="text" name="keyword" data-column="all">
<button type="button" class="reset">Reset</button>
<button type="button" data-filter-column="all">13</button>
<button class="bad" type="button" data-filter-column="all" title="See &quot;Notes&quot; on why the second row isn't highlighted">~ee</button>
<button type="button" data-filter-column="all">br?n</button>
<button type="button" data-filter-column="all">br*n</button>
<button type="button" data-filter-column="all">aaron|bruce</button>
<button type="button" data-filter-column="all">aaron && 2</button>
<table id="table" class="tablesorter">
<thead>
<tr>
<th>Rank</th>
<th class="filter-match">First Name</th>
<th>Last Name</th>
<th>Age</th>
<th>Total</th>
<th>Discount</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>Philip Aaron Wong</td><td>Johnson Sr Esq</td><td>25</td><td>$5.95</td><td>22%</td><td>Jun 26, 2004 7:22 AM</td></tr>
<tr><td>11</td><td>Aáron</td><td>Hibert</td><td>12</td><td>$2.99</td><td>5%</td><td>Aug 21, 2009 12:21 PM</td></tr>
<tr><td>12</td><td>Brandon Clark</td><td>Henry Jr</td><td>51</td><td>$42.29</td><td>18%</td><td>Oct 13, 2000 1:15 PM</td></tr>
<tr><td>111</td><td>Peter</td><td>Párker</td><td>28</td><td>$9.99</td><td>20%</td><td>Jul 6, 2006 8:14 AM</td></tr>
<tr><td>21</td><td>John</td><td>Hood</td><td>33</td><td>$19.99</td><td>25%</td><td>Dec 10, 2002 5:14 AM</td></tr>
<tr><td>013</td><td>Clark</td><td>Kènt Sr.</td><td>18</td><td>$15.89</td><td>44%</td><td>Jan 12, 2003 11:14 AM</td></tr>
<tr><td>005</td><td>Bruce</td><td>Almighty Esq</td><td>45</td><td>$153.19</td><td>44%</td><td>Jan 18, 2021 9:12 AM</td></tr>
<tr><td>10</td><td>Alex</td><td>Dumāss</td><td>13</td><td>$5.29</td><td>4%</td><td>Jan 8, 2012 5:11 PM</td></tr>
<tr><td>16</td><td>Jim</td><td>Franco</td><td>24</td><td>$14.19</td><td>14%</td><td>Jan 14, 2004 11:23 AM</td></tr>
<tr><td>166</td><td>Brüce Lee</td><td>Evans</td><td>22</td><td>$13.19</td><td>11%</td><td>Jan 18, 2007 9:12 AM</td></tr>
<tr><td>100</td><td>Brenda Dexter</td><td>McMasters</td><td>18</td><td>$55.20</td><td>15%</td><td>Feb 12, 2010 7:23 PM</td></tr>
<tr><td>55</td><td>Dennís</td><td>Bronson</td><td>65</td><td>$123.00</td><td>32%</td><td>Jan 20, 2001 1:12 PM</td></tr>
<tr><td>9</td><td>Martha</td><td>delFuego</td><td>25</td><td>$22.09</td><td>17%</td><td>Jun 11, 2011 10:55 AM</td></tr>
</tbody>
</table>
<h1>Demo: Without the Filter Widget</h1>
<br>
Search/Highlight all columns: <input id="table2-search" type="search">
<button class="table2 reset2" type="button">Reset</button>
<button class="table2" type="button">13</button>
<button class="table2 bad" type="button" title="See &quot;Notes&quot; on why the &quot;005 Bruce Almighty&quot; row isn't highlighted">~ee</button>
<button class="table2" type="button">br?n</button>
<button class="table2" type="button">br*n</button>
<button class="table2" type="button">aaron|bruce</button>
<button class="table2" type="button">aaron && 2</button>
<table id="table2" class="tablesorter">
<thead>
<tr>
<th>Rank</th>
<th class="filter-match">First Name</th>
<th>Last Name</th>
<th>Age</th>
<th>Total</th>
<th>Discount</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>Philip Aaron Wong</td><td>Johnson Sr Esq</td><td>25</td><td>$5.95</td><td>22%</td><td>Jun 26, 2004 7:22 AM</td></tr>
<tr><td>11</td><td>Aáron</td><td>Hibert</td><td>12</td><td>$2.99</td><td>5%</td><td>Aug 21, 2009 12:21 PM</td></tr>
<tr><td>12</td><td>Brandon Clark</td><td>Henry Jr</td><td>51</td><td>$42.29</td><td>18%</td><td>Oct 13, 2000 1:15 PM</td></tr>
<tr><td>111</td><td>Peter</td><td>Párker</td><td>28</td><td>$9.99</td><td>20%</td><td>Jul 6, 2006 8:14 AM</td></tr>
<tr><td>21</td><td>John</td><td>Hood</td><td>33</td><td>$19.99</td><td>25%</td><td>Dec 10, 2002 5:14 AM</td></tr>
<tr><td>013</td><td>Clark</td><td>Kènt Sr.</td><td>18</td><td>$15.89</td><td>44%</td><td>Jan 12, 2003 11:14 AM</td></tr>
<tr><td>005</td><td>Bruce</td><td>Almighty Esq</td><td>45</td><td>$153.19</td><td>44%</td><td>Jan 18, 2021 9:12 AM</td></tr>
<tr><td>10</td><td>Alex</td><td>Dumāss</td><td>13</td><td>$5.29</td><td>4%</td><td>Jan 8, 2012 5:11 PM</td></tr>
<tr><td>16</td><td>Jim</td><td>Franco</td><td>24</td><td>$14.19</td><td>14%</td><td>Jan 14, 2004 11:23 AM</td></tr>
<tr><td>166</td><td>Brüce Lee</td><td>Evans</td><td>22</td><td>$13.19</td><td>11%</td><td>Jan 18, 2007 9:12 AM</td></tr>
<tr><td>100</td><td>Brenda Dexter</td><td>McMasters</td><td>18</td><td>$55.20</td><td>15%</td><td>Feb 12, 2010 7:23 PM</td></tr>
<tr><td>55</td><td>Dennís</td><td>Bronson</td><td>65</td><td>$123.00</td><td>32%</td><td>Jan 20, 2001 1:12 PM</td></tr>
<tr><td>9</td><td>Martha</td><td>delFuego</td><td>25</td><td>$22.09</td><td>17%</td><td>Jun 11, 2011 10:55 AM</td></tr>
</tbody>
</table>
<h1>Page Header</h1>
<div>
<pre class="prettyprint lang-html">&lt;!-- blue theme stylesheet --&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;css/theme.blue.css&quot;&gt;
&lt;!-- tablesorter plugin --&gt;
&lt;script src=&quot;js/jquery-latest.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;js/jquery.tablesorter.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;js/jquery.tablesorter.widgets.js&quot;&gt;&lt;/script&gt;
&lt;!-- jquery.mark.js & tablesorter mark widget loaded after the plugin --&gt;
&lt;script src=&quot;js/jquery.mark.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;js/widget-mark.js&quot;&gt;&lt;/script&gt;</pre>
</div>
<h1>CSS</h1>
<div id="css">
<pre class="prettyprint lang-css"></pre>
</div>
<h1>Javascript</h1>
<div id="javascript">
<pre class="prettyprint lang-javascript"></pre>
</div>
</div>
</body>
</html>

View File

@ -484,6 +484,7 @@
</li>
<li><a href="example-widget-header-titles.html">Header titles widget</a> (v2.15.6; <span class="version updated">v2.24.4</span>).</li>
<li><span class="label label-info">Beta</span> <a href="example-widget-lazyload.html">Lazyload widget</a> (<span class="version">v2.24.0</span>; <span class="version updated">v2.25.7</span>).</li>
<li><a href="example-widget-mark.html">Mark widget</a> (<span class="version">v2.27.0</span>).</li>
<li><a href="example-widget-math.html">Math widget</a> (<span class="version">v2.16</span>; <span class="version updated">v2.25.5</span>).</li>
<li>
<a href="example-widget-output.html">Output widget</a> (<span class="version">v2.16</span>; <span class="version updated">v2.25.2</span>).

135
js/widgets/widget-mark.js Normal file
View File

@ -0,0 +1,135 @@
/*! Widget: mark.js - updated 7/27/2016 (v2.27.0) *//*
* Requires tablesorter v2.8+ and jQuery 1.7+
* by Rob Garrison
*/
;( function( $ ) {
'use strict';
var ts = $.tablesorter;
ts.mark = {
init : function( c, wo ) {
if ( typeof $.fn.mark === 'function' ) {
var tmp,
update = c.widgetOptions.mark_tsUpdate;
c.$table.on( 'filterEnd.tsmark' + ( update ? ' ' + update : '' ), function( e, filters ) {
// filterEnd passes "config" as the param
ts.mark.update( c, e.type === 'filterEnd' ? '' : filters );
});
// Regex to split up a query
tmp = '(?:<|=|>|\\||\"|' + "\\'|" +
'\\s+(?:&&|-|' +
( ts.language.and || 'and' ) + '|' +
( ts.language.or || 'or' ) + '|' +
( ts.language.to || 'to' ) + ')\\s+)';
ts.mark.regex.filter = new RegExp(tmp, 'gim');
} else {
console.warn('Widget-mark not initialized: missing "jquery.mark.js"');
}
},
regex : {
mark : /^mark_(.+)$/,
// test for regex (e.g. "/(lorem|ipsum)/gi")
pure : /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/
},
checkRegex : function( regex ) {
if ( regex instanceof RegExp ) {
// prevent lock up of mark.js (see https://github.com/julmot/mark.js/issues/55)
var result = '\u0001\u0002\u0003\u0004\u0005'.match( regex );
return result === null || result.length < 5;
}
return false;
},
cleanMatches : function( matches ) {
var results = [],
indx = matches && matches.length || 0;
while ( indx-- ) {
if ( matches[indx] !== "" ) {
results[ results.length ] = matches[ indx ];
}
}
return results;
},
update : function( c, filters ) {
var options = {},
regex = ts.mark.regex,
$rows = c.$table
.find( 'tbody tr' )
.unmark()
.not( '.' + ( c.widgetOptions.filter_filteredRow || 'filtered' ) ),
filters = filters || $.tablesorter.getFilters( c.$table );
// extract & save mark options from widgetOptions (prefixed with "mark_")
// update dynamically
$.each( filters, function( indx, filter ) {
if ( filter ) {
var testRegex = null,
matches = filter,
useRegex = false,
col = indx === c.columns ? '' : ':nth-child(' + ( indx + 1 ) + ')';
// regular expression entered
if ( regex.pure.test( filter ) ) {
matches = regex.pure.exec( filter );
// ignore "all" matches (i.e. /.*/)
if (matches[1] === '.*') {
matches[1] = '';
}
try {
// make sure to include global flag when testing regex
testRegex = new RegExp( matches[ 1 ], 'gim' );
matches = new RegExp( matches[ 1 ], matches[ 2 ] );
} catch (err) {
matches = null;
}
if ( ts.mark.checkRegex( testRegex ) ) {
$rows.children( col ).markRegExp( matches, options );
}
// matches is either null, invalid, or done my markRegExp
return;
}
// all special querys (or, and, wild cards & fuzzy)
// regex seems to not be consistent here; so use string indexOf
// fuzzy or wild card matches
if ( filter.indexOf( '~' ) === 0 ) {
useRegex = true;
// fuzzy search separate each letter
matches = filter.replace( /~/g, '' ).split( '' );
} else {
// wild card matching
if ( filter.indexOf( '?' ) > -1 ) {
useRegex = true;
filter = filter.replace( /\?/g, '\\S{1}' );
}
if ( filter.indexOf( '*' ) > -1 ) {
useRegex = true;
filter = filter.replace( /\*/g, '\\S*' );
}
matches = filter.split( regex.filter );
}
if ( useRegex && matches && matches.length ) {
matches = new RegExp( ts.mark.cleanMatches( matches ).join( '.*' ), 'gim' );
if ( ts.mark.checkRegex( matches ) ) {
$rows.children( col ).markRegExp( matches, options );
}
} else {
// pass an array of matches
$rows.children( col ).mark( ts.mark.cleanMatches( matches ), options );
}
}
});
}
};
ts.addWidget({
id: 'mark',
options: {
mark_tsUpdate : "markUpdate"
},
init : function( table, thisWidget, c, wo ) {
ts.mark.init( c, wo );
},
remove : function( table, c ) {
var update = c.widgetOptions.mark_tsUpdate;
c.$table.off( 'filterEnd.tsmark' + ( update ? ' ' + update : '' ) );
}
});
})( jQuery );