SEO Smart Links - Version 3.0

Version Description

  • Major update of the code
  • Fixed all reported bugs
  • Performance improvements
  • Many new features
  • If oyu like this update please rate the plugin!
Download this release

Release Info

Developer freediver
Plugin Icon 128x128 SEO Smart Links
Version 3.0
Comparing to
See all releases

Code changes from version 2.7.8 to 3.0

Files changed (29) hide show
  1. i/asc.gif +0 -0
  2. i/bg.gif +0 -0
  3. i/bin.gif +0 -0
  4. i/desc.gif +0 -0
  5. i/first.png +0 -0
  6. i/help.png +0 -0
  7. i/home.png +0 -0
  8. i/icon.png +0 -0
  9. i/last.png +0 -0
  10. i/logo.png +0 -0
  11. i/more.png +0 -0
  12. i/mwp250_2.png +0 -0
  13. i/next.png +0 -0
  14. i/p1.png +0 -0
  15. i/page_edit.gif +0 -0
  16. i/paypal.gif +0 -0
  17. i/prev.png +0 -0
  18. i/seoimages125_v2.jpg +0 -0
  19. i/seosmart125.png +0 -0
  20. i/twit.png +0 -0
  21. js/filter.js +92 -0
  22. js/jquery.tablednd_0_5.js +382 -0
  23. js/pager.js +189 -0
  24. js/quicksearch.js +146 -0
  25. js/seo-links.js +251 -0
  26. js/tablesorter.js +852 -0
  27. readme.txt +9 -2
  28. seo-links.php +1752 -675
  29. sml.css +128 -0
i/asc.gif ADDED
Binary file
i/bg.gif ADDED
Binary file
i/bin.gif ADDED
Binary file
i/desc.gif ADDED
Binary file
i/first.png ADDED
Binary file
i/help.png DELETED
Binary file
i/home.png DELETED
Binary file
i/icon.png ADDED
Binary file
i/last.png ADDED
Binary file
i/logo.png ADDED
Binary file
i/more.png DELETED
Binary file
i/mwp250_2.png ADDED
Binary file
i/next.png ADDED
Binary file
i/p1.png DELETED
Binary file
i/page_edit.gif ADDED
Binary file
i/paypal.gif DELETED
Binary file
i/prev.png ADDED
Binary file
i/seoimages125_v2.jpg ADDED
Binary file
i/seosmart125.png ADDED
Binary file
i/twit.png DELETED
Binary file
js/filter.js ADDED
@@ -0,0 +1,92 @@
1
+ /*
2
+ * Copyright (c) 2008 Greg Weber greg at gregweber.info
3
+ * Dual licensed under the MIT and GPL licenses:
4
+ * http://www.opensource.org/licenses/mit-license.php
5
+ * http://www.gnu.org/licenses/gpl.html
6
+ *
7
+ * documentation at http://gregweber.info/projects/uitablefilter
8
+ *
9
+ * allows table rows to be filtered (made invisible)
10
+ * <code>
11
+ * t = jQuery('table')
12
+ * jQuery.uiTableFilter( t, phrase )
13
+ * </code>
14
+ * arguments:
15
+ * jQuery object containing table rows
16
+ * phrase to search for
17
+ * optional arguments:
18
+ * column to limit search too (the column title in the table header)
19
+ * ifHidden - callback to execute if one or more elements was hidden
20
+ */
21
+ (function(jQuery) {
22
+ jQuery.uiTableFilter = function(jq, phrase, column, ifHidden){
23
+ var new_hidden = false;
24
+ if( this.last_phrase === phrase ) return false;
25
+
26
+ var phrase_length = phrase.length;
27
+ var words = phrase.toLowerCase().split(" ");
28
+
29
+ // these function pointers may change
30
+ var matches = function(elem) { elem.show() }
31
+ var noMatch = function(elem) { elem.hide(); new_hidden = true }
32
+ var getText = function(elem) { return elem.text() }
33
+
34
+ if( column ) {
35
+ var index = null;
36
+ jq.find("thead > tr:last > th").each( function(i){
37
+ if( jQuery.trim(jQuery(this).text()) == column ){
38
+ index = i; return false;
39
+ }
40
+ });
41
+ if( index == null ) throw("given column: " + column + " not found")
42
+
43
+ getText = function(elem){ return jQuery(elem.find(
44
+ ("td:eq(" + index + ")") )).text()
45
+ }
46
+ }
47
+
48
+ // if added one letter to last time,
49
+ // just check newest word and only need to hide
50
+ if( (words.size > 1) && (phrase.substr(0, phrase_length - 1) ===
51
+ this.last_phrase) ) {
52
+
53
+ if( phrase[-1] === " " )
54
+ { this.last_phrase = phrase; return false; }
55
+
56
+ var words = words[-1]; // just search for the newest word
57
+
58
+ // only hide visible rows
59
+ matches = function(elem) {;}
60
+ var elems = jq.find("tbody > tr:visible")
61
+ }
62
+ else {
63
+ new_hidden = true;
64
+ var elems = jq.find("tbody > tr")
65
+ }
66
+
67
+ elems.each(function(){
68
+ var elem = jQuery(this);
69
+ jQuery.uiTableFilter.has_words( getText(elem), words, false ) ?
70
+ matches(elem) : noMatch(elem);
71
+ });
72
+
73
+ last_phrase = phrase;
74
+ if( ifHidden && new_hidden ) ifHidden();
75
+ return jq;
76
+ };
77
+
78
+ // caching for speedup
79
+ jQuery.uiTableFilter.last_phrase = ""
80
+
81
+ // not jQuery dependent
82
+ // "" [""] -> Boolean
83
+ // "" [""] Boolean -> Boolean
84
+ jQuery.uiTableFilter.has_words = function( str, words, caseSensitive )
85
+ {
86
+ var text = caseSensitive ? str : str.toLowerCase();
87
+ for (var i=0; i < words.length; i++) {
88
+ if (text.indexOf(words[i]) === -1) return false;
89
+ }
90
+ return true;
91
+ }
92
+ }) (jQuery);
js/jquery.tablednd_0_5.js ADDED
@@ -0,0 +1,382 @@
1
+ /**
2
+ * TableDnD plug-in for JQuery, allows you to drag and drop table rows
3
+ * You can set up various options to control how the system will work
4
+ * Copyright (c) Denis Howlett <denish@isocra.com>
5
+ * Licensed like jQuery, see http://docs.jquery.com/License.
6
+ *
7
+ * Configuration options:
8
+ *
9
+ * onDragStyle
10
+ * This is the style that is assigned to the row during drag. There are limitations to the styles that can be
11
+ * associated with a row (such as you can't assign a border--well you can, but it won't be
12
+ * displayed). (So instead consider using onDragClass.) The CSS style to apply is specified as
13
+ * a map (as used in the jQuery css(...) function).
14
+ * onDropStyle
15
+ * This is the style that is assigned to the row when it is dropped. As for onDragStyle, there are limitations
16
+ * to what you can do. Also this replaces the original style, so again consider using onDragClass which
17
+ * is simply added and then removed on drop.
18
+ * onDragClass
19
+ * This class is added for the duration of the drag and then removed when the row is dropped. It is more
20
+ * flexible than using onDragStyle since it can be inherited by the row cells and other content. The default
21
+ * is class is tDnD_whileDrag. So to use the default, simply customise this CSS class in your
22
+ * stylesheet.
23
+ * onDrop
24
+ * Pass a function that will be called when the row is dropped. The function takes 2 parameters: the table
25
+ * and the row that was dropped. You can work out the new order of the rows by using
26
+ * table.rows.
27
+ * onDragStart
28
+ * Pass a function that will be called when the user starts dragging. The function takes 2 parameters: the
29
+ * table and the row which the user has started to drag.
30
+ * onAllowDrop
31
+ * Pass a function that will be called as a row is over another row. If the function returns true, allow
32
+ * dropping on that row, otherwise not. The function takes 2 parameters: the dragged row and the row under
33
+ * the cursor. It returns a boolean: true allows the drop, false doesn't allow it.
34
+ * scrollAmount
35
+ * This is the number of pixels to scroll if the user moves the mouse cursor to the top or bottom of the
36
+ * window. The page should automatically scroll up or down as appropriate (tested in IE6, IE7, Safari, FF2,
37
+ * FF3 beta
38
+ * dragHandle
39
+ * This is the name of a class that you assign to one or more cells in each row that is draggable. If you
40
+ * specify this class, then you are responsible for setting cursor: move in the CSS and only these cells
41
+ * will have the drag behaviour. If you do not specify a dragHandle, then you get the old behaviour where
42
+ * the whole row is draggable.
43
+ *
44
+ * Other ways to control behaviour:
45
+ *
46
+ * Add class="nodrop" to any rows for which you don't want to allow dropping, and class="nodrag" to any rows
47
+ * that you don't want to be draggable.
48
+ *
49
+ * Inside the onDrop method you can also call $.tableDnD.serialize() this returns a string of the form
50
+ * <tableID>[]=<rowID1>&<tableID>[]=<rowID2> so that you can send this back to the server. The table must have
51
+ * an ID as must all the rows.
52
+ *
53
+ * Other methods:
54
+ *
55
+ * $("...").tableDnDUpdate()
56
+ * Will update all the matching tables, that is it will reapply the mousedown method to the rows (or handle cells).
57
+ * This is useful if you have updated the table rows using Ajax and you want to make the table draggable again.
58
+ * The table maintains the original configuration (so you don't have to specify it again).
59
+ *
60
+ * $("...").tableDnDSerialize()
61
+ * Will serialize and return the serialized string as above, but for each of the matching tables--so it can be
62
+ * called from anywhere and isn't dependent on the currentTable being set up correctly before calling
63
+ *
64
+ * Known problems:
65
+ * - Auto-scoll has some problems with IE7 (it scrolls even when it shouldn't), work-around: set scrollAmount to 0
66
+ *
67
+ * Version 0.2: 2008-02-20 First public version
68
+ * Version 0.3: 2008-02-07 Added onDragStart option
69
+ * Made the scroll amount configurable (default is 5 as before)
70
+ * Version 0.4: 2008-03-15 Changed the noDrag/noDrop attributes to nodrag/nodrop classes
71
+ * Added onAllowDrop to control dropping
72
+ * Fixed a bug which meant that you couldn't set the scroll amount in both directions
73
+ * Added serialize method
74
+ * Version 0.5: 2008-05-16 Changed so that if you specify a dragHandle class it doesn't make the whole row
75
+ * draggable
76
+ * Improved the serialize method to use a default (and settable) regular expression.
77
+ * Added tableDnDupate() and tableDnDSerialize() to be called when you are outside the table
78
+ */
79
+ jQuery.tableDnD = {
80
+ /** Keep hold of the current table being dragged */
81
+ currentTable : null,
82
+ /** Keep hold of the current drag object if any */
83
+ dragObject: null,
84
+ /** The current mouse offset */
85
+ mouseOffset: null,
86
+ /** Remember the old value of Y so that we don't do too much processing */
87
+ oldY: 0,
88
+
89
+ /** Actually build the structure */
90
+ build: function(options) {
91
+ // Set up the defaults if any
92
+
93
+ this.each(function() {
94
+ // This is bound to each matching table, set up the defaults and override with user options
95
+ this.tableDnDConfig = jQuery.extend({
96
+ onDragStyle: null,
97
+ onDropStyle: null,
98
+ // Add in the default class for whileDragging
99
+ onDragClass: "tDnD_whileDrag",
100
+ onDrop: null,
101
+ onDragStart: null,
102
+ scrollAmount: 5,
103
+ serializeRegexp: /[^\-]*#x2F;, // The regular expression to use to trim row IDs
104
+ serializeParamName: null, // If you want to specify another parameter name instead of the table ID
105
+ dragHandle: null // If you give the name of a class here, then only Cells with this class will be draggable
106
+ }, options || {});
107
+ // Now make the rows draggable
108
+ jQuery.tableDnD.makeDraggable(this);
109
+ });
110
+
111
+ // Now we need to capture the mouse up and mouse move event
112
+ // We can use bind so that we don't interfere with other event handlers
113
+ jQuery(document)
114
+ .bind('mousemove', jQuery.tableDnD.mousemove)
115
+ .bind('mouseup', jQuery.tableDnD.mouseup);
116
+
117
+ // Don't break the chain
118
+ return this;
119
+ },
120
+
121
+ /** This function makes all the rows on the table draggable apart from those marked as "NoDrag" */
122
+ makeDraggable: function(table) {
123
+ var config = table.tableDnDConfig;
124
+ if (table.tableDnDConfig.dragHandle) {
125
+ // We only need to add the event to the specified cells
126
+ var cells = jQuery("td."+table.tableDnDConfig.dragHandle, table);
127
+ cells.each(function() {
128
+ // The cell is bound to "this"
129
+ jQuery(this).mousedown(function(ev) {
130
+ jQuery.tableDnD.dragObject = this.parentNode;
131
+ jQuery.tableDnD.currentTable = table;
132
+ jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev);
133
+ if (config.onDragStart) {
134
+ // Call the onDrop method if there is one
135
+ config.onDragStart(table, this);
136
+ }
137
+ return false;
138
+ });
139
+ })
140
+ } else {
141
+ // For backwards compatibility, we add the event to the whole row
142
+ var rows = jQuery("tr", table); // get all the rows as a wrapped set
143
+ rows.each(function() {
144
+ // Iterate through each row, the row is bound to "this"
145
+ var row = jQuery(this);
146
+ if (! row.hasClass("nodrag")) {
147
+ row.mousedown(function(ev) {
148
+ if (ev.target.tagName == "TD") {
149
+ jQuery.tableDnD.dragObject = this;
150
+ jQuery.tableDnD.currentTable = table;
151
+ jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev);
152
+ if (config.onDragStart) {
153
+ // Call the onDrop method if there is one
154
+ config.onDragStart(table, this);
155
+ }
156
+ return false;
157
+ }
158
+ }).css("cursor", "move"); // Store the tableDnD object
159
+ }
160
+ });
161
+ }
162
+ },
163
+
164
+ updateTables: function() {
165
+ this.each(function() {
166
+ // this is now bound to each matching table
167
+ if (this.tableDnDConfig) {
168
+ jQuery.tableDnD.makeDraggable(this);
169
+ }
170
+ })
171
+ },
172
+
173
+ /** Get the mouse coordinates from the event (allowing for browser differences) */
174
+ mouseCoords: function(ev){
175
+ if(ev.pageX || ev.pageY){
176
+ return {x:ev.pageX, y:ev.pageY};
177
+ }
178
+ return {
179
+ x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
180
+ y:ev.clientY + document.body.scrollTop - document.body.clientTop
181
+ };
182
+ },
183
+
184
+ /** Given a target element and a mouse event, get the mouse offset from that element.
185
+ To do this we need the element's position and the mouse position */
186
+ getMouseOffset: function(target, ev) {
187
+ ev = ev || window.event;
188
+
189
+ var docPos = this.getPosition(target);
190
+ var mousePos = this.mouseCoords(ev);
191
+ return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
192
+ },
193
+
194
+ /** Get the position of an element by going up the DOM tree and adding up all the offsets */
195
+ getPosition: function(e){
196
+ var left = 0;
197
+ var top = 0;
198
+ /** Safari fix -- thanks to Luis Chato for this! */
199
+ if (e.offsetHeight == 0) {
200
+ /** Safari 2 doesn't correctly grab the offsetTop of a table row
201
+ this is detailed here:
202
+ http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/
203
+ the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild.
204
+ note that firefox will return a text node as a first child, so designing a more thorough
205
+ solution may need to take that into account, for now this seems to work in firefox, safari, ie */
206
+ e = e.firstChild; // a table cell
207
+ }
208
+
209
+ while (e.offsetParent){
210
+ left += e.offsetLeft;
211
+ top += e.offsetTop;
212
+ e = e.offsetParent;
213
+ }
214
+
215
+ left += e.offsetLeft;
216
+ top += e.offsetTop;
217
+
218
+ return {x:left, y:top};
219
+ },
220
+
221
+ mousemove: function(ev) {
222
+ if (jQuery.tableDnD.dragObject == null) {
223
+ return;
224
+ }
225
+
226
+ var dragObj = jQuery(jQuery.tableDnD.dragObject);
227
+ var config = jQuery.tableDnD.currentTable.tableDnDConfig;
228
+ var mousePos = jQuery.tableDnD.mouseCoords(ev);
229
+ var y = mousePos.y - jQuery.tableDnD.mouseOffset.y;
230
+ //auto scroll the window
231
+ var yOffset = window.pageYOffset;
232
+ if (document.all) {
233
+ // Windows version
234
+ //yOffset=document.body.scrollTop;
235
+ if (typeof document.compatMode != 'undefined' &&
236
+ document.compatMode != 'BackCompat') {
237
+ yOffset = document.documentElement.scrollTop;
238
+ }
239
+ else if (typeof document.body != 'undefined') {
240
+ yOffset=document.body.scrollTop;
241
+ }
242
+
243
+ }
244
+
245
+ if (mousePos.y-yOffset < config.scrollAmount) {
246
+ window.scrollBy(0, -config.scrollAmount);
247
+ } else {
248
+ var windowHeight = window.innerHeight ? window.innerHeight
249
+ : document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight;
250
+ if (windowHeight-(mousePos.y-yOffset) < config.scrollAmount) {
251
+ window.scrollBy(0, config.scrollAmount);
252
+ }
253
+ }
254
+
255
+
256
+ if (y != jQuery.tableDnD.oldY) {
257
+ // work out if we're going up or down...
258
+ var movingDown = y > jQuery.tableDnD.oldY;
259
+ // update the old value
260
+ jQuery.tableDnD.oldY = y;
261
+ // update the style to show we're dragging
262
+ if (config.onDragClass) {
263
+ dragObj.addClass(config.onDragClass);
264
+ } else {
265
+ dragObj.css(config.onDragStyle);
266
+ }
267
+ // If we're over a row then move the dragged row to there so that the user sees the
268
+ // effect dynamically
269
+ var currentRow = jQuery.tableDnD.findDropTargetRow(dragObj, y);
270
+ if (currentRow) {
271
+ // TODO worry about what happens when there are multiple TBODIES
272
+ if (movingDown && jQuery.tableDnD.dragObject != currentRow) {
273
+ jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow.nextSibling);
274
+ } else if (! movingDown && jQuery.tableDnD.dragObject != currentRow) {
275
+ jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow);
276
+ }
277
+ }
278
+ }
279
+
280
+ return false;
281
+ },
282
+
283
+ /** We're only worried about the y position really, because we can only move rows up and down */
284
+ findDropTargetRow: function(draggedRow, y) {
285
+ var rows = jQuery.tableDnD.currentTable.rows;
286
+ for (var i=0; i<rows.length; i++) {
287
+ var row = rows[i];
288
+ var rowY = this.getPosition(row).y;
289
+ var rowHeight = parseInt(row.offsetHeight)/2;
290
+ if (row.offsetHeight == 0) {
291
+ rowY = this.getPosition(row.firstChild).y;
292
+ rowHeight = parseInt(row.firstChild.offsetHeight)/2;
293
+ }
294
+ // Because we always have to insert before, we need to offset the height a bit
295
+ if ((y > rowY - rowHeight) && (y < (rowY + rowHeight))) {
296
+ // that's the row we're over
297
+ // If it's the same as the current row, ignore it
298
+ if (row == draggedRow) {return null;}
299
+ var config = jQuery.tableDnD.currentTable.tableDnDConfig;
300
+ if (config.onAllowDrop) {
301
+ if (config.onAllowDrop(draggedRow, row)) {
302
+ return row;
303
+ } else {
304
+ return null;
305
+ }
306
+ } else {
307
+ // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic)
308
+ var nodrop = jQuery(row).hasClass("nodrop");
309
+ if (! nodrop) {
310
+ return row;
311
+ } else {
312
+ return null;
313
+ }
314
+ }
315
+ return row;
316
+ }
317
+ }
318
+ return null;
319
+ },
320
+
321
+ mouseup: function(e) {
322
+ if (jQuery.tableDnD.currentTable && jQuery.tableDnD.dragObject) {
323
+ var droppedRow = jQuery.tableDnD.dragObject;
324
+ var config = jQuery.tableDnD.currentTable.tableDnDConfig;
325
+ // If we have a dragObject, then we need to release it,
326
+ // The row will already have been moved to the right place so we just reset stuff
327
+ if (config.onDragClass) {
328
+ jQuery(droppedRow).removeClass(config.onDragClass);
329
+ } else {
330
+ jQuery(droppedRow).css(config.onDropStyle);
331
+ }
332
+ jQuery.tableDnD.dragObject = null;
333
+ if (config.onDrop) {
334
+ // Call the onDrop method if there is one
335
+ config.onDrop(jQuery.tableDnD.currentTable, droppedRow);
336
+ }
337
+ jQuery.tableDnD.currentTable = null; // let go of the table too
338
+ }
339
+ },
340
+
341
+ serialize: function() {
342
+ if (jQuery.tableDnD.currentTable) {
343
+ return jQuery.tableDnD.serializeTable(jQuery.tableDnD.currentTable);
344
+ } else {
345
+ return "Error: No Table id set, you need to set an id on your table and every row";
346
+ }
347
+ },
348
+
349
+ serializeTable: function(table) {
350
+ var result = "";
351
+ var tableId = table.id;
352
+ var rows = table.rows;
353
+ for (var i=0; i<rows.length; i++) {
354
+ if (result.length > 0) result += "&";
355
+ var rowId = rows[i].id;
356
+ if (rowId && rowId && table.tableDnDConfig && table.tableDnDConfig.serializeRegexp) {
357
+ rowId = rowId.match(table.tableDnDConfig.serializeRegexp)[0];
358
+ }
359
+
360
+ result += tableId + '[]=' + rowId;
361
+ }
362
+ return result;
363
+ },
364
+
365
+ serializeTables: function() {
366
+ var result = "";
367
+ this.each(function() {
368
+ // this is now bound to each matching table
369
+ result += jQuery.tableDnD.serializeTable(this);
370
+ });
371
+ return result;
372
+ }
373
+
374
+ }
375
+
376
+ jQuery.fn.extend(
377
+ {
378
+ tableDnD : jQuery.tableDnD.build,
379
+ tableDnDUpdate : jQuery.tableDnD.updateTables,
380
+ tableDnDSerialize: jQuery.tableDnD.serializeTables
381
+ }
382
+ );
js/pager.js ADDED
@@ -0,0 +1,189 @@
1
+ (function(jQuery) {
2
+ jQuery.extend({
3
+ tablesorterPager: new function() {
4
+
5
+ function updatePageDisplay(c) {
6
+
7
+ var s = jQuery(c.cssPageDisplay,c.container).val((c.page+1) + c.seperator + c.totalPages);
8
+
9
+ }
10
+
11
+ function setPageSize(table,size) {
12
+ var c = table.config;
13
+ c.size = size;
14
+ c.totalPages = Math.ceil(c.totalRows / c.size);
15
+ c.pagerPositionSet = false;
16
+ moveToPage(table);
17
+ fixPosition(table);
18
+ }
19
+
20
+ function fixPosition(table) {
21
+ var c = table.config;
22
+ if(!c.pagerPositionSet && c.positionFixed) {
23
+ var c = table.config, o = jQuery(table);
24
+ if(o.offset) {
25
+ c.container.css({
26
+ top: o.offset().top + o.height() + 'px',
27
+ position: 'absolute'
28
+ });
29
+ }
30
+ c.pagerPositionSet = true;
31
+ }
32
+ }
33
+
34
+ function moveToFirstPage(table) {
35
+ var c = table.config;
36
+ c.page = 0;
37
+ moveToPage(table);
38
+ }
39
+
40
+ function moveToLastPage(table) {
41
+ var c = table.config;
42
+
43
+ c.page = (c.totalPages-1);
44
+ moveToPage(table);
45
+ }
46
+
47
+ function moveToNextPage(table) {
48
+ var c = table.config;
49
+ c.page++;
50
+
51
+ if(c.page >= (c.totalPages-1)) {
52
+ c.page = (c.totalPages-1);
53
+ }
54
+ moveToPage(table);
55
+ }
56
+
57
+ function moveToPrevPage(table) {
58
+ var c = table.config;
59
+
60
+ c.page--;
61
+ if(c.page <= 0) {
62
+ c.page = 0;
63
+ }
64
+ moveToPage(table);
65
+ }
66
+
67
+
68
+ function moveToPage(table) {
69
+ var c = table.config;
70
+ if(c.page < 0 || c.page > (c.totalPages-1)) {
71
+ c.page = 0;
72
+ }
73
+
74
+ renderTable(table,c.rowsCopy);
75
+ }
76
+
77
+ function renderTable(table,rows) {
78
+
79
+ var c = table.config;
80
+ var l = rows.length;
81
+ var s = (c.page * c.size);
82
+ var e = (s + c.size);
83
+ if(e > rows.length ) {
84
+ e = rows.length;
85
+ }
86
+ //alert(c.size);
87
+
88
+ var tableBody = jQuery(table.tBodies[0]);
89
+
90
+ // clear the table body
91
+
92
+ jQuery.tablesorter.clearTableBody(table);
93
+
94
+ for(var i = s; i < e; i++) {
95
+
96
+ //tableBody.append(rows[i]);
97
+
98
+ var o = rows[i];
99
+ var l = o.length;
100
+ for(var j=0; j < l; j++) {
101
+
102
+ tableBody[0].appendChild(o[j]);
103
+
104
+ }
105
+ }
106
+
107
+ fixPosition(table,tableBody);
108
+
109
+ jQuery(table).trigger("applyWidgets");
110
+
111
+ if( c.page >= c.totalPages ) {
112
+ moveToLastPage(table);
113
+ }
114
+
115
+ updatePageDisplay(c);
116
+ }
117
+
118
+ this.appender = function(table,rows) {
119
+
120
+ var c = table.config;
121
+
122
+ c.rowsCopy = rows;
123
+ c.totalRows = rows.length;
124
+ c.totalPages = Math.ceil(c.totalRows / c.size);
125
+
126
+ renderTable(table,rows);
127
+ };
128
+
129
+ this.defaults = {
130
+ size: 25,
131
+ offset: 0,
132
+ page: 0,
133
+ totalRows: 0,
134
+ totalPages: 0,
135
+ container: null,
136
+ cssNext: '.next',
137
+ cssPrev: '.prev',
138
+ cssFirst: '.first',
139
+ cssLast: '.last',
140
+ cssPageDisplay: '.pagedisplay',
141
+ cssPageSize: '.pagesize',
142
+ seperator: "/",
143
+ positionFixed: false,
144
+ appender: this.appender
145
+ };
146
+
147
+ this.construct = function(settings) {
148
+
149
+ return this.each(function() {
150
+
151
+ config = jQuery.extend(this.config, jQuery.tablesorterPager.defaults, settings);
152
+
153
+ var table = this, pager = config.container;
154
+
155
+ jQuery(this).trigger("appendCache");
156
+
157
+ config.size = parseInt(jQuery(".pagesize",pager).val());
158
+
159
+ jQuery(config.cssFirst,pager).click(function() {
160
+ moveToFirstPage(table);
161
+ return false;
162
+ });
163
+ jQuery(config.cssNext,pager).click(function() {
164
+ moveToNextPage(table);
165
+ return false;
166
+ });
167
+ jQuery(config.cssPrev,pager).click(function() {
168
+ moveToPrevPage(table);
169
+ return false;
170
+ });
171
+ jQuery(config.cssLast,pager).click(function() {
172
+ moveToLastPage(table);
173
+ return false;
174
+ });
175
+ jQuery(config.cssPageSize,pager).change(function() {
176
+ setPageSize(table,parseInt(jQuery(this).val()));
177
+ return false;
178
+ });
179
+ });
180
+ };
181
+
182
+ }
183
+ });
184
+ // extend plugin scope
185
+ jQuery.fn.extend({
186
+ tablesorterPager: jQuery.tablesorterPager.construct
187
+ });
188
+
189
+ })(jQuery);
js/quicksearch.js ADDED
@@ -0,0 +1,146 @@
1
+ jQuery(function ($) {
2
+ $.fn.quicksearch = function (target, opt) {
3
+
4
+ var timeout, cache, rowcache, jq_results, val = '', e = this, options = $.extend({
5
+ delay: 100,
6
+ selector: null,
7
+ stripeRows: null,
8
+ loader: null,
9
+ noResults: '',
10
+ bind: 'keyup',
11
+ onBefore: function () {
12
+ return;
13
+ },
14
+ onAfter: function () {
15
+ return;
16
+ },
17
+ show: function () {
18
+ this.style.display = "";
19
+ },
20
+ hide: function () {
21
+ this.style.display = "none";
22
+ }
23
+ }, opt);
24
+
25
+ this.go = function () {
26
+
27
+ var i = 0, noresults = true, vals = val.toLowerCase().split(' ');
28
+
29
+ var rowcache_length = rowcache.length;
30
+ for (var i = 0; i < rowcache_length; i++)
31
+ {
32
+ if (this.test(vals, cache[i]) || val == "") {
33
+ options.show.apply(rowcache[i]);
34
+ noresults = false;
35
+ } else {
36
+ options.hide.apply(rowcache[i]);
37
+ }
38
+ }
39
+
40
+ if (noresults) {
41
+ this.results(false);
42
+ } else {
43
+ this.results(true);
44
+ this.stripe();
45
+ }
46
+
47
+ this.loader(false);
48
+ options.onAfter();
49
+
50
+ return this;
51
+ };
52
+
53
+ this.stripe = function () {
54
+
55
+ if (typeof options.stripeRows === "object" && options.stripeRows !== null)
56
+ {
57
+ var joined = options.stripeRows.join(' ');
58
+ var stripeRows_length = options.stripeRows.length;
59
+
60
+ jq_results.not(':hidden').each(function (i) {
61
+ $(this).removeClass(joined).addClass(options.stripeRows[i % stripeRows_length]);
62
+ });
63
+ }
64
+
65
+ return this;
66
+ };
67
+
68
+ this.strip_html = function (input) {
69
+ var output = input.replace(new RegExp('<[^<]+\>', 'g'), "");
70
+ output = $.trim(output.toLowerCase());
71
+ return output;
72
+ };
73
+
74
+ this.results = function (bool) {
75
+ if (typeof options.noResults === "string" && options.noResults !== "") {
76
+ if (bool) {
77
+ $(options.noResults).hide();
78
+ } else {
79
+ $(options.noResults).show();
80
+ }
81
+ }
82
+ return this;
83
+ };
84
+
85
+ this.loader = function (bool) {
86
+ if (typeof options.loader === "string" && options.loader !== "") {
87
+ (bool) ? $(options.loader).show() : $(options.loader).hide();
88
+ }
89
+ return this;
90
+ };
91
+
92
+ this.test = function (vals, t) {
93
+ for (var i = 0; i < vals.length; i += 1) {
94
+ if (t.indexOf(vals[i]) === -1) {
95
+ return false;
96
+ }
97
+ }
98
+ return true;
99
+ };
100
+
101
+ this.cache = function () {
102
+
103
+ jq_results = $(target);
104
+
105
+ if (typeof options.noResults === "string" && options.noResults !== "") {
106
+ jq_results = jq_results.not(options.noResults);
107
+ }
108
+
109
+ var t = (typeof options.selector === "string") ? jq_results.find(options.selector) : $(target).not(options.noResults);
110
+ cache = t.map(function () {
111
+ return e.strip_html(this.innerHTML);
112
+ });
113
+
114
+ rowcache = jq_results.map(function () {
115
+ return this;
116
+ });
117
+
118
+ return this.go();
119
+ };
120
+
121
+ this.trigger = function () {
122
+ this.loader(true);
123
+ options.onBefore();
124
+
125
+ window.clearTimeout(timeout);
126
+ timeout = window.setTimeout(function () {
127
+ e.go();
128
+ }, options.delay);
129
+
130
+ return this;
131
+ };
132
+
133
+ this.cache();
134
+ this.results(true);
135
+ this.stripe();
136
+ this.loader(false);
137
+
138
+ return this.each(function () {
139
+ $(this).bind(options.bind, function () {
140
+ val = $(this).val();
141
+ e.trigger();
142
+ });
143
+ });
144
+
145
+ };
146
+ });
js/seo-links.js ADDED
@@ -0,0 +1,251 @@
1
+ jQuery(function() {
2
+ var theTable = jQuery('table#mySortable');
3
+
4
+ jQuery("#filter").keyup(function(e) {
5
+
6
+ if (e.keyCode == 13)
7
+ jQuery.uiTableFilter(theTable, this.value);
8
+
9
+ jQuery("#mySortable tbody tr:eq(0)").hide();
10
+
11
+ });
12
+
13
+ });
14
+
15
+ jQuery(document).ready(function() {
16
+
17
+ jQuery("#datatable")
18
+ .tablesorter({ } )
19
+ .tablesorterPager({container: jQuery("#pager")});
20
+
21
+
22
+
23
+ refresh_me();
24
+
25
+ jQuery("input").bind("keypress", function(e) {
26
+ if (e.keyCode == 13)
27
+ return false;
28
+ });
29
+
30
+ jQuery("a#edit_all").bind("click", function() {
31
+ jQuery("#customkey").toggle(0);
32
+
33
+
34
+ });
35
+
36
+ jQuery("input").bind("keypress", function(e) {
37
+ if (e.keyCode == 13)
38
+ return false;
39
+ });
40
+ jQuery("input[name=addword]").keypress(function(e) {
41
+ if (e.keyCode == 13) {
42
+
43
+ jQuery("#saveadd").click();
44
+ }
45
+ if (e.keyCode == 27) {
46
+
47
+ jQuery("#canceladd").click();
48
+ }
49
+ });
50
+
51
+ jQuery("input[name=addurl]").keypress(function(e) {
52
+ if (e.keyCode == 13) {
53
+
54
+ jQuery("#saveadd").click();
55
+ }
56
+ if (e.keyCode == 27) {
57
+
58
+ jQuery("#canceladd").click();
59
+ }
60
+ });
61
+
62
+ });
63
+
64
+ function put_data() {
65
+
66
+ var tmp = '';
67
+
68
+ jQuery('table#mySortable tbody tr').each(function(i) {
69
+ //iterate tr
70
+ if (i) {
71
+ jQuery(this).find('td').each(function(i) {
72
+ //iterate td
73
+ elem = jQuery(this);
74
+ if (elem.text())
75
+ if (elem.is(".word") || elem.is(".url") || elem.is(".redir")) {
76
+
77
+ if (i == 1 || i == 2)
78
+ tmp += '|';//SEOSmartOptions.separator;
79
+
80
+ tmp += elem.text();
81
+
82
+ }
83
+ if (i==2)
84
+ tmp+="\n";
85
+ });
86
+ }
87
+
88
+ });
89
+
90
+ document.getElementById('customkey').value = tmp;
91
+
92
+ }
93
+
94
+ function refresh_me() {
95
+
96
+ jQuery("table#mySortable").tableDnD({
97
+ onDrop: function(table, row) {
98
+ //jQuery("table#mySortable tr").removeClass('odd');
99
+ //jQuery("table#mySortable tr:visible:odd").addClass('odd');
100
+ put_data();
101
+
102
+ }
103
+ });
104
+
105
+
106
+ jQuery(".editlink").click(function() {
107
+
108
+ jQuery(this).hide();
109
+ var datapos = jQuery(this).parent().parent().prevAll().length;
110
+ var editpos = datapos + 1;
111
+
112
+
113
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.savelink").show();
114
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.cancellink").show();
115
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.removelink").hide();
116
+
117
+ var word = jQuery("#mySortable tbody tr:eq(" + datapos + ") td.word").text();
118
+ var word_input = '<span name="editword" style="display: none;">' + word + '</span><input type="text" name="editword" value="' + word + '" />';
119
+ var url = jQuery("#mySortable tbody tr:eq(" + datapos + ") td.url").text();
120
+ var url_input = '<span name="editlink" style="display: none;">' + url + '</span><input type="text" name="editlink" value="' + url + '" />';
121
+ var redir = jQuery("#mySortable tbody tr:eq(" + datapos + ") td.redir").text();
122
+ var redir_input = '<span name="editredir" style="display: none;">' + redir + '</span><input type="text" name="editredir" value="' + redir + '" />';
123
+
124
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td.word").html(word_input);
125
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td.url").html(url_input);
126
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td.redir").html(redir_input);
127
+
128
+ jQuery("input").bind("keypress", function(e) {
129
+ if (e.keyCode == 13)
130
+ return false;
131
+ });
132
+ jQuery("input[name=editword]").keypress(function(e) {
133
+ if (e.keyCode == 13) {
134
+
135
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.savelink").click();
136
+ }
137
+ if (e.keyCode == 27) {
138
+
139
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.cancellink").click();
140
+ }
141
+ });
142
+
143
+ jQuery("input[name=editlink]").keypress(function(e) {
144
+ if (e.keyCode == 13) {
145
+
146
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.savelink").click();
147
+ }
148
+ if (e.keyCode == 27) {
149
+
150
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.cancellink").click();
151
+ }
152
+ });
153
+
154
+ });
155
+
156
+ jQuery(".cancellink").click(function() {
157
+ var datapos = jQuery(this).parent().parent().prevAll().length;
158
+
159
+ var editword = jQuery("#mySortable tbody tr:eq(" + datapos + ") td span[name=editword]").text();
160
+ var editlink = jQuery("#mySortable tbody tr:eq(" + datapos + ") td span[name=editlink]").text();
161
+ var editredir = jQuery("#mySortable tbody tr:eq(" + datapos + ") td span[name=editredir]").text();
162
+
163
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td.word").html(editword);
164
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td.url").html(editlink);
165
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td.redir").html(editredir);
166
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.savelink").hide();
167
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.cancellink").hide();
168
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.removelink").show();
169
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.editlink").show();
170
+
171
+ put_data();
172
+ });
173
+
174
+ jQuery(".removelink").click(function() {
175
+ var datapos = jQuery(this).parent().parent().prevAll().length;
176
+
177
+ jQuery("#mySortable tbody tr:eq(" + datapos + ")").remove();
178
+
179
+ jQuery("#updatemessage").text("Keyword removed").fadeOut(2000, function() {
180
+ jQuery(this).css('display', 'block').text("");
181
+ });
182
+ put_data();
183
+
184
+
185
+ });
186
+
187
+ jQuery(".savelink").click(function() {
188
+ var datapos = jQuery(this).parent().parent().prevAll().length;
189
+
190
+ var editword = jQuery("#mySortable tbody tr:eq(" + datapos + ") td input[name=editword]").val();
191
+ var editlink = jQuery("#mySortable tbody tr:eq(" + datapos + ") td input[name=editlink]").val();
192
+ var editredir = jQuery("#mySortable tbody tr:eq(" + datapos + ") td input[name=editredir]").val();
193
+
194
+ //alert(editword);
195
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td.word").text(editword);
196
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td.url").text(editlink);
197
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td.redir").text(editredir);
198
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.savelink").hide();
199
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.cancellink").hide();
200
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.removelink").show();
201
+ jQuery("#mySortable tbody tr:eq(" + datapos + ") td a.editlink").show();
202
+
203
+ jQuery("#updatemessage").text("Keyword updated").fadeOut(2000, function() {
204
+ jQuery(this).css('display', 'block').text("");
205
+ });
206
+
207
+ put_data();
208
+
209
+
210
+ });
211
+
212
+ jQuery("#addrowbutton").unbind('click').click(function() {
213
+ jQuery("#addrow").show();
214
+ });
215
+
216
+ jQuery("#canceladd").click(function() {
217
+ jQuery("#addrow").hide();
218
+ });
219
+
220
+ jQuery("#saveadd").click(function() {
221
+
222
+ jQuery("#mySortable tbody tr:eq(0)").clone(true).insertAfter("#mySortable tbody tr:eq(0)");
223
+
224
+ var addword = jQuery("#addrow input[name=addword]").val();
225
+ var addurl = jQuery("#addrow input[name=addurl]").val();
226
+ var addredir = jQuery("#addrow input[name=addredir]").val();
227
+
228
+ jQuery("#mySortable tbody tr:eq(1)").show();
229
+ jQuery("#mySortable tbody tr:eq(1) .word").text(addword);
230
+ jQuery("#mySortable tbody tr:eq(1) .url").text(addurl);
231
+ jQuery("#mySortable tbody tr:eq(1) .redir").text(addredir);
232
+
233
+ jQuery("#addrow input[name=addword]").val("");
234
+ jQuery("#addrow input[name=addurl]").val("http://");
235
+ jQuery("#addrow input[name=addredir]").val("");
236
+
237
+ jQuery("#addrow").hide();
238
+
239
+ jQuery("#updatemessage").text("Keyword added").fadeOut(2000, function() {
240
+ jQuery(this).css('display', 'block').text("");
241
+ });
242
+
243
+ // sort on the first column
244
+ jQuery("#mySortable").trigger("applyWidgets", "zebra");
245
+
246
+ put_data();
247
+
248
+ });
249
+
250
+ }
251
+ //end refresh me
js/tablesorter.js ADDED
@@ -0,0 +1,852 @@
<
1
+ /*
2
+ *
3
+ * TableSorter 2.0 - Client-side table sorting with ease!
4
+ * Version 2.0.3
5
+ * @requires jQuery v1.2.3
6
+ *
7
+ * Copyright (c) 2007 Christian Bach
8
+ * Examples and docs at: http://tablesorter.com
9
+ * Dual licensed under the MIT and GPL licenses:
10
+ * http://www.opensource.org/licenses/mit-license.php
11
+ * http://www.gnu.org/licenses/gpl.html
12
+ *
13
+ */
14
+ /**
15
+ *
16
+ * @description Create a sortable table with multi-column sorting capabilitys
17
+ *
18
+ * @example $('table').tablesorter();
19
+ * @desc Create a simple tablesorter interface.
20
+ *
21
+ * @example $('table').tablesorter({ sortList:[[0,0],[1,0]] });
22
+ * @desc Create a tablesorter interface and sort on the first and secound column in ascending order.
23
+ *
24
+ * @example $('table').tablesorter({ headers: { 0: { sorter: false}, 1: {sorter: false} } });
25
+ * @desc Create a tablesorter interface and disableing the first and secound column headers.
26
+ *
27
+ * @example $('table').tablesorter({ 0: {sorter:"integer"}, 1: {sorter:"currency"} });
28
+ * @desc Create a tablesorter interface and set a column parser for the first and secound column.
29
+ *
30
+ *
31
+ * @param Object settings An object literal containing key/value pairs to provide optional settings.
32
+ *
33
+ * @option String cssHeader (optional) A string of the class name to be appended to sortable tr elements in the thead of the table.
34
+ * Default value: "header"
35
+ *
36
+ * @option String cssAsc (optional) A string of the class name to be appended to sortable tr elements in the thead on a ascending sort.
37
+ * Default value: "headerSortUp"
38
+ *
39
+ * @option String cssDesc (optional) A string of the class name to be appended to sortable tr elements in the thead on a descending sort.
40
+ * Default value: "headerSortDown"
41
+ *
42
+ * @option String sortInitialOrder (optional) A string of the inital sorting order can be asc or desc.
43
+ * Default value: "asc"
44
+ *
45
+ * @option String sortMultisortKey (optional) A string of the multi-column sort key.
46
+ * Default value: "shiftKey"
47
+ *
48
+ * @option String textExtraction (optional) A string of the text-extraction method to use.
49
+ * For complex html structures inside td cell set this option to "complex",
50
+ * on large tables the complex option can be slow.
51
+ * Default value: "simple"
52
+ *
53
+ * @option Object headers (optional) An array containing the forces sorting rules.
54
+ * This option let's you specify a default sorting rule.
55
+ * Default value: null
56
+ *
57
+ * @option Array sortList (optional) An array containing the forces sorting rules.
58
+ * This option let's you specify a default sorting rule.
59
+ * Default value: null
60
+ *
61
+ * @option Array sortForce (optional) An array containing forced sorting rules.
62
+ * This option let's you specify a default sorting rule, which is prepended to user-selected rules.
63
+ * Default value: null
64
+ *
65
+ * @option Array sortAppend (optional) An array containing forced sorting rules.
66
+ * This option let's you specify a default sorting rule, which is appended to user-selected rules.
67
+ * Default value: null
68
+ *
69
+ * @option Boolean widthFixed (optional) Boolean flag indicating if tablesorter should apply fixed widths to the table columns.
70
+ * This is usefull when using the pager companion plugin.
71
+ * This options requires the dimension jquery plugin.
72
+ * Default value: false
73
+ *
74
+ * @option Boolean cancelSelection (optional) Boolean flag indicating if tablesorter should cancel selection of the table headers text.
75
+ * Default value: true
76
+ *
77
+ * @option Boolean debug (optional) Boolean flag indicating if tablesorter should display debuging information usefull for development.
78
+ *
79
+ * @type jQuery
80
+ *
81
+ * @name tablesorter
82
+ *
83
+ * @cat Plugins/Tablesorter
84
+ *
85
+ * @author Christian Bach/christian.bach@polyester.se
86
+ */
87
+
88
+ (function($) {
89
+ $.extend({
90
+ tablesorter: new function() {
91
+
92
+ var parsers = [], widgets = [];
93
+
94
+ this.defaults = {
95
+ cssHeader: "header",
96
+ cssAsc: "headerSortUp",
97
+ cssDesc: "headerSortDown",
98
+ sortInitialOrder: "asc",
99
+ sortMultiSortKey: "shiftKey",
100
+ sortForce: null,
101
+ sortAppend: null,
102
+ textExtraction: "simple",
103
+ parsers: {},
104
+ widgets: [],
105
+ widgetZebra: {css: ["even","odd"]},
106
+ headers: {},
107
+ widthFixed: false,
108
+ cancelSelection: true,
109
+ sortList: [],
110
+ headerList: [],
111
+ dateFormat: "us",
112
+ decimal: '.',
113
+ debug: false
114
+ };
115
+
116
+ /* debuging utils */
117
+ function benchmark(s,d) {
118
+ log(s + "," + (new Date().getTime() - d.getTime()) + "ms");
119
+ }
120
+
121
+ this.benchmark = benchmark;
122
+
123
+ function log(s) {
124
+ if (typeof console != "undefined" && typeof console.debug != "undefined") {
125
+ console.log(s);
126
+ } else {
127
+ alert(s);
128
+ }
129
+ }
130
+
131
+ /* parsers utils */
132
+ function buildParserCache(table,$headers) {
133
+
134
+ if(table.config.debug) { var parsersDebug = ""; }
135
+
136
+ var rows = table.tBodies[0].rows;
137
+
138
+ if(table.tBodies[0].rows[0]) {
139
+
140
+ var list = [], cells = rows[0].cells, l = cells.length;
141
+
142
+ for (var i=0;i < l; i++) {
143
+ var p = false;
144
+
145
+ if($.metadata && ($($headers[i]).metadata() && $($headers[i]).metadata().sorter) ) {
146
+
147
+ p = getParserById($($headers[i]).metadata().sorter);
148
+
149
+ } else if((table.config.headers[i] && table.config.headers[i].sorter)) {
150
+
151
+ p = getParserById(table.config.headers[i].sorter);
152
+ }
153
+ if(!p) {
154
+ p = detectParserForColumn(table,cells[i]);
155
+ }
156
+
157
+ if(table.config.debug) { parsersDebug += "column:" + i + " parser:" +p.id + "\n"; }
158
+
159
+ list.push(p);
160
+ }
161
+ }
162
+
163
+ if(table.config.debug) { log(parsersDebug); }
164
+
165
+ return list;
166
+ };
167
+
168
+ function detectParserForColumn(table,node) {
169
+ var l = parsers.length;
170
+ for(var i=1; i < l; i++) {
171
+ if(parsers[i].is($.trim(getElementText(table.config,node)),table,node)) {
172
+ return parsers[i];
173
+ }
174
+ }
175
+ // 0 is always the generic parser (text)
176
+ return parsers[0];
177
+ }
178
+
179
+ function getParserById(name) {
180
+ var l = parsers.length;
181
+ for(var i=0; i < l; i++) {
182
+ if(parsers[i].id.toLowerCase() == name.toLowerCase()) {
183
+ return parsers[i];
184
+ }
185
+ }
186
+ return false;
187
+ }
188
+
189
+ /* utils */
190
+ function buildCache(table) {
191
+
192
+ if(table.config.debug) { var cacheTime = new Date(); }
193
+
194
+
195
+ var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0,
196
+ totalCells = (table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length) || 0,
197
+ parsers = table.config.parsers,
198
+ cache = {row: [], normalized: []};
199
+
200
+ for (var i=0;i < totalRows; ++i) {
201
+
202
+ /** Add the table data to main data array */
203
+ var c = table.tBodies[0].rows[i], cols = [];
204
+
205
+ cache.row.push($(c));
206
+
207
+ for(var j=0; j < totalCells; ++j) {
208
+ cols.push(parsers[j].format(getElementText(table.config,c.cells[j]),table,c.cells[j]));
209
+ }
210
+
211
+ cols.push(i); // add position for rowCache
212
+ cache.normalized.push(cols);
213
+ cols = null;
214
+ };
215
+
216
+ if(table.config.debug) { benchmark("Building cache for " + totalRows + " rows:", cacheTime); }
217
+
218
+ return cache;
219
+ };
220
+
221
+ function getElementText(config,node) {
222
+
223
+ if(!node) return "";
224
+
225
+ var t = "";
226
+
227
+ if(config.textExtraction == "simple") {
228
+ if(node.childNodes[0] && node.childNodes[0].hasChildNodes()) {
229
+ t = node.childNodes[0].innerHTML;
230
+ } else {
231
+ t = node.innerHTML;
232
+ }
233
+ } else {
234
+ if(typeof(config.textExtraction) == "function") {
235
+ t = config.textExtraction(node);
236
+ } else {
237
+ t = $(node).text();
238
+ }
239
+ }
240
+ return t;
241
+ }
242
+
243
+ function appendToTable(table,cache) {
244
+
245
+ if(table.config.debug) {var appendTime = new Date()}
246
+
247
+ var c = cache,
248
+ r = c.row,
249
+ n= c.normalized,
250
+ totalRows = n.length,
251
+ checkCell = (n[0].length-1),
252
+ tableBody = $(table.tBodies[0]),
253
+ rows = [];
254
+
255
+ for (var i=0;i < totalRows; i++) {
256
+ rows.push(r[n[i][checkCell]]);
257
+ if(!table.config.appender) {
258
+
259
+ var o = r[n[i][checkCell]];
260
+ var l = o.length;
261
+ for(var j=0; j < l; j++) {
262
+
263
+ tableBody[0].appendChild(o[j]);
264
+
265
+ }
266
+
267
+ //tableBody.append(r[n[i][checkCell]]);
268
+ }
269
+ }
270
+
271
+ if(table.config.appender) {
272
+
273
+ table.config.appender(table,rows);
274
+ }
275
+
276
+ rows = null;
277
+
278
+ if(table.config.debug) { benchmark("Rebuilt table:", appendTime); }
279
+
280
+ //apply table widgets
281
+ applyWidget(table);
282
+
283
+ // trigger sortend
284
+ setTimeout(function() {
285
+ $(table).trigger("sortEnd");
286
+ },0);
287
+
288
+ };
289
+
290
+ function buildHeaders(table) {
291
+
292
+ if(table.config.debug) { var time = new Date(); }
293
+
294
+ var meta = ($.metadata) ? true : false, tableHeadersRows = [];
295
+
296
+ for(var i = 0; i < table.tHead.rows.length; i++) { tableHeadersRows[i]=0; };
297
+
298
+ $tableHeaders = $("thead th",table);
299
+
300
+ $tableHeaders.each(function(index) {
301
+
302
+ this.count = 0;
303
+ this.column = index;
304
+ this.order = formatSortingOrder(table.config.sortInitialOrder);
305
+
306
+ if(checkHeaderMetadata(this) || checkHeaderOptions(table,index)) this.sortDisabled = true;
307
+
308
+ if(!this.sortDisabled) {
309
+ $(this).addClass(table.config.cssHeader);
310
+ }
311
+
312
+ // add cell to headerList
313
+ table.config.headerList[index]= this;
314
+ });
315
+
316
+ if(table.config.debug) { benchmark("Built headers:", time); log($tableHeaders); }
317
+
318
+ return $tableHeaders;
319
+
320
+ };
321
+
322
+ function checkCellColSpan(table, rows, row) {
323
+ var arr = [], r = table.tHead.rows, c = r[row].cells;
324
+
325
+ for(var i=0; i < c.length; i++) {
326
+ var cell = c[i];
327
+
328
+ if ( cell.colSpan > 1) {
329
+ arr = arr.concat(checkCellColSpan(table, headerArr,row++));
330
+ } else {
331
+ if(table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row+1])) {
332
+ arr.push(cell);
333
+ }
334
+ //headerArr[row] = (i+row);
335
+ }
336
+ }
337
+ return arr;
338
+ };
339
+
340
+ function checkHeaderMetadata(cell) {
341
+ if(($.metadata) && ($(cell).metadata().sorter === false)) { return true; };
342
+ return false;
343
+ }
344
+
345
+ function checkHeaderOptions(table,i) {
346
+ if((table.config.headers[i]) && (table.config.headers[i].sorter === false)) { return true; };
347
+ return false;
348
+ }
349
+
350
+ function applyWidget(table) {
351
+ var c = table.config.widgets;
352
+ var l = c.length;
353
+ for(var i=0; i < l; i++) {
354
+
355
+ getWidgetById(c[i]).format(table);
356
+ }
357
+
358
+ }
359
+
360
+ function getWidgetById(name) {
361
+ var l = widgets.length;
362
+ for(var i=0; i < l; i++) {
363
+ if(widgets[i].id.toLowerCase() == name.toLowerCase() ) {
364
+ return widgets[i];
365
+ }
366
+ }
367
+ };
368
+
369
+ function formatSortingOrder(v) {
370
+
371
+ if(typeof(v) != "Number") {
372
+ i = (v.toLowerCase() == "desc") ? 1 : 0;
373
+ } else {
374
+ i = (v == (0 || 1)) ? v : 0;
375
+ }
376
+ return i;
377
+ }
378
+
379
+ function isValueInArray(v, a) {
380
+ var l = a.length;
381
+ for(var i=0; i < l; i++) {
382
+ if(a[i][0] == v) {
383
+ return true;
384
+ }
385
+ }
386
+ return false;
387
+ }
388
+
389
+ function setHeadersCss(table,$headers, list, css) {
390
+ // remove all header information
391
+ $headers.removeClass(css[0]).removeClass(css[1]);
392
+
393
+ var h = [];
394
+ $headers.each(function(offset) {
395
+ if(!this.sortDisabled) {
396
+ h[this.column] = $(this);
397
+ }
398
+ });
399
+
400
+ var l = list.length;
401
+ for(var i=0; i < l; i++) {
402
+ h[list[i][0]].addClass(css[list[i][1]]);
403
+ }
404
+ }
405
+
406
+ function fixColumnWidth(table,$headers) {
407
+ var c = table.config;
408
+ if(c.widthFixed) {
409
+ var colgroup = $('<colgroup>');
410
+ $("tr:first td",table.tBodies[0]).each(function() {
411
+ colgroup.append($('<col>').css('width',$(this).width()));
412
+ });
413
+ $(table).prepend(colgroup);
414
+ };
415
+ }
416
+
417
+ function updateHeaderSortCount(table,sortList) {
418
+ var c = table.config, l = sortList.length;
419
+ for(var i=0; i < l; i++) {
420
+ var s = sortList[i], o = c.headerList[s[0]];
421
+ o.count = s[1];
422
+ o.count++;
423
+ }
424
+ }
425
+
426
+ /* sorting methods */
427
+ function multisort(table,sortList,cache) {
428
+
429
+ if(table.config.debug) { var sortTime = new Date(); }
430
+
431
+ var dynamicExp = "var sortWrapper = function(a,b) {", l = sortList.length;
432
+
433
+ for(var i=0; i < l; i++) {
434
+
435
+ var c = sortList[i][0];
436
+ var order = sortList[i][1];
437
+ var s = (getCachedSortType(table.config.parsers,c) == "text") ? ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ? "sortNumeric" : "sortNumericDesc");
438
+
439
+ var e = "e" + i;
440
+
441
+ dynamicExp += "var " + e + " = " + s + "(a[" + c + "],b[" + c + "]); ";
442
+ dynamicExp += "if(" + e + ") { return " + e + "; } ";
443
+ dynamicExp += "else { ";
444
+ }
445
+
446
+ // if value is the same keep orignal order
447
+ var orgOrderCol = cache.normalized[0].length - 1;
448
+ dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];";
449
+
450
+ for(var i=0; i < l; i++) {
451
+ dynamicExp += "}; ";
452
+ }
453
+
454
+ dynamicExp += "return 0; ";
455
+ dynamicExp += "}; ";
456
+
457
+ eval(dynamicExp);
458
+
459
+ cache.normalized.sort(sortWrapper);
460
+
461
+ if(table.config.debug) { benchmark("Sorting on " + sortList.toString() + " and dir " + order+ " time:", sortTime); }
462
+
463
+ return cache;
464
+ };
465
+
466
+ function sortText(a,b) {
467
+ return ((a < b) ? -1 : ((a > b) ? 1 : 0));
468
+ };
469
+
470
+ function sortTextDesc(a,b) {
471
+ return ((b < a) ? -1 : ((b > a) ? 1 : 0));
472
+ };
473
+
474
+ function sortNumeric(a,b) {
475
+ return a-b;
476
+ };
477
+
478
+ function sortNumericDesc(a,b) {
479
+ return b-a;
480
+ };
481
+
482
+ function getCachedSortType(parsers,i) {
483
+ return parsers[i].type;
484
+ };
485
+
486
+ /* public methods */
487
+ this.construct = function(settings) {
488
+
489
+ return this.each(function() {
490
+
491
+ if(!this.tHead || !this.tBodies) return;
492
+
493
+ var $this, $document,$headers, cache, config, shiftDown = 0, sortOrder;
494
+
495
+ this.config = {};
496
+
497
+ config = $.extend(this.config, $.tablesorter.defaults, settings);
498
+
499
+ // store common expression for speed
500
+ $this = $(this);
501
+
502
+ // build headers
503
+ $headers = buildHeaders(this);
504
+
505
+ // try to auto detect column type, and store in tables config
506
+ this.config.parsers = buildParserCache(this,$headers);
507
+
508
+
509
+ // build the cache for the tbody cells
510
+ cache = buildCache(this);
511
+
512
+ // get the css class names, could be done else where.
513
+ var sortCSS = [config.cssDesc,config.cssAsc];
514
+
515
+ // fixate columns if the users supplies the fixedWidth option
516
+ fixColumnWidth(this);
517
+
518
+ // apply event handling to headers
519
+ // this is to big, perhaps break it out?
520
+ $headers.click(function(e) {
521
+
522
+ $this.trigger("sortStart");
523
+
524
+ var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0;
525
+
526
+ if(!this.sortDisabled && totalRows > 0) {
527
+
528
+
529
+ // store exp, for speed
530
+ var $cell = $(this);
531
+
532
+ // get current column index
533
+ var i = this.column;
534
+
535
+ // get current column sort order
536
+ this.order = this.count++ % 2;
537
+
538
+ // user only whants to sort on one column
539
+ if(!e[config.sortMultiSortKey]) {
540
+
541
+ // flush the sort list
542
+ config.sortList = [];
543
+
544
+ if(config.sortForce != null) {
545
+ var a = config.sortForce;
546
+ for(var j=0; j < a.length; j++) {
547
+ if(a[j][0] != i) {
548
+ config.sortList.push(a[j]);
549
+ }
550
+ }
551
+ }
552
+
553
+ // add column to sort list
554
+ config.sortList.push([i,this.order]);
555
+
556
+ // multi column sorting
557
+ } else {
558
+ // the user has clicked on an all ready sortet column.
559
+ if(isValueInArray(i,config.sortList)) {
560
+
561
+ // revers the sorting direction for all tables.
562
+ for(var j=0; j < config.sortList.length; j++) {
563
+ var s = config.sortList[j], o = config.headerList[s[0]];
564
+ if(s[0] == i) {
565
+ o.count = s[1];
566
+ o.count++;
567
+ s[1] = o.count % 2;
568
+ }
569
+ }
570
+ } else {
571
+ // add column to sort list array
572
+ config.sortList.push([i,this.order]);
573
+ }
574
+ };
575
+ setTimeout(function() {
576
+ //set css for headers
577
+ setHeadersCss($this[0],$headers,config.sortList,sortCSS);
578
+ appendToTable($this[0],multisort($this[0],config.sortList,cache));
579
+ },1);
580
+ // stop normal event by returning false
581
+ return false;
582
+ }
583
+ // cancel selection
584
+ }).mousedown(function() {
585
+ if(config.cancelSelection) {
586
+ this.onselectstart = function() {return false};
587
+ return false;
588
+ }
589
+ });
590
+
591
+ // apply easy methods that trigger binded events
592
+ $this.bind("update",function() {
593
+
594
+ // rebuild parsers.
595
+ this.config.parsers = buildParserCache(this,$headers);
596
+
597
+ // rebuild the cache map
598
+ cache = buildCache(this);
599
+
600
+ }).bind("sorton",function(e,list) {
601
+
602
+ $(this).trigger("sortStart");
603
+
604
+ config.sortList = list;
605
+
606
+ // update and store the sortlist
607
+ var sortList = config.sortList;
608
+
609
+ // update header count index
610
+ updateHeaderSortCount(this,sortList);
611
+
612
+ //set css for headers
613
+ setHeadersCss(this,$headers,sortList,sortCSS);
614
+
615
+
616
+ // sort the table and append it to the dom
617
+ appendToTable(this,multisort(this,sortList,cache));
618
+
619
+ }).bind("appendCache",function() {
620
+
621
+ appendToTable(this,cache);
622
+
623
+ }).bind("applyWidgetId",function(e,id) {
624
+
625
+ getWidgetById(id).format(this);
626
+
627
+ }).bind("applyWidgets",function() {
628
+ // apply widgets
629
+ applyWidget(this);
630
+ });
631
+
632
+ if($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) {
633
+ config.sortList = $(this).metadata().sortlist;
634
+ }
635
+ // if user has supplied a sort list to constructor.
636
+ if(config.sortList.length > 0) {
637
+ $this.trigger("sorton",[config.sortList]);
638
+ }
639
+
640
+ // apply widgets
641
+ applyWidget(this);
642
+ });
643
+ };
644
+
645
+ this.addParser = function(parser) {
646
+ var l = parsers.length, a = true;
647
+ for(var i=0; i < l; i++) {
648
+ if(parsers[i].id.toLowerCase() == parser.id.toLowerCase()) {
649
+ a = false;
650
+ }
651
+ }
652
+ if(a) { parsers.push(parser); };
653
+ };
654
+
655
+ this.addWidget = function(widget) {
656
+ widgets.push(widget);
657
+ };
658
+
659
+ this.formatFloat = function(s) {
660
+ var i = parseFloat(s);
661
+ return (isNaN(i)) ? 0 : i;
662
+ };
663
+ this.formatInt = function(s) {
664
+ var i = parseInt(s);
665
+ return (isNaN(i)) ? 0 : i;
666
+ };
667
+
668
+ this.isDigit = function(s,config) {
669
+ var DECIMAL = '\\' + config.decimal;
670
+ var exp = '/(^[+]?0(' + DECIMAL +'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)' + DECIMAL +'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*' + DECIMAL +'0+$)/';
671
+ return RegExp(exp).test($.trim(s));
672
+ };
673
+
674
+ this.clearTableBody = function(table) {
675
+ if($.browser.msie) {
676
+ function empty() {
677
+ while ( this.firstChild ) this.removeChild( this.firstChild );
678
+ }
679
+ empty.apply(table.tBodies[0]);
680
+ } else {
681
+ table.tBodies[0].innerHTML = "";
682
+ }
683
+ };
684
+ }
685
+ });
686
+
687
+ // extend plugin scope
688
+ $.fn.extend({
689
+ tablesorter: $.tablesorter.construct
690
+ });
691
+
692
+ var ts = $.tablesorter;
693
+
694
+ // add default parsers
695
+ ts.addParser({
696
+ id: "text",
697
+ is: function(s) {
698
+ return true;
699
+ },
700
+ format: function(s) {
701
+ return $.trim(s.toLowerCase());
702
+ },
703
+ type: "text"
704
+ });
705
+
706
+ ts.addParser({
707
+ id: "digit",
708
+ is: function(s,table) {
709
+ var c = table.config;
710
+ return $.tablesorter.isDigit(s,c);
711
+ },
712
+ format: function(s) {
713
+ return $.tablesorter.formatFloat(s);
714
+ },
715
+ type: "numeric"
716
+ });
717
+
718
+ ts.addParser({
719
+ id: "currency",
720
+ is: function(s) {
721
+ return /^[£$€?.]/.test(s);
722
+ },
723
+ format: function(s) {
724
+ return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9.]/g),""));
725
+ },
726
+ type: "numeric"
727
+ });
728
+
729
+ ts.addParser({
730
+ id: "ipAddress",
731
+ is: function(s) {
732
+ return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}#x2F;.test(s);
733
+ },
734
+ format: function(s) {
735
+ var a = s.split("."), r = "", l = a.length;
736
+ for(var i = 0; i < l; i++) {
737
+ var item = a[i];
738
+ if(item.length == 2) {
739
+ r += "0" + item;
740
+ } else {
741
+ r += item;
742
+ }
743
+ }
744
+ return $.tablesorter.formatFloat(r);
745
+ },
746
+ type: "numeric"
747
+ });
748
+
749
+ ts.addParser({
750
+ id: "url",
751
+ is: function(s) {
752
+ return /^(https?|ftp|file):\/\/#x2F;.test(s);
753
+ },
754
+ format: function(s) {
755
+ return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));
756
+ },
757
+ type: "text"
758
+ });
759
+
760
+ ts.addParser({
761
+ id: "isoDate",
762
+ is: function(s) {
763
+ return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}#x2F;.test(s);
764
+ },
765
+ format: function(s) {
766
+ return $.tablesorter.formatFloat((s != "") ? new Date(s.replace(new RegExp(/-/g),"/")).getTime() : "0");
767
+ },
768
+ type: "numeric"
769
+ });
770
+
771
+ ts.addParser({
772
+ id: "percent",
773
+ is: function(s) {
774
+ return /\%#x2F;.test($.trim(s));
775
+ },
776
+ format: function(s) {
777
+ return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));
778
+ },
779
+ type: "numeric"
780
+ });
781
+
782
+ ts.addParser({
783
+ id: "usLongDate",
784
+ is: function(s) {
785
+ return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))#x2F;));
786
+ },
787
+ format: function(s) {
788
+ return $.tablesorter.formatFloat(new Date(s).getTime());
789
+ },
790
+ type: "numeric"
791
+ });
792
+
793
+ ts.addParser({
794
+ id: "shortDate",
795
+ is: function(s) {
796
+ return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);
797
+ },
798
+ format: function(s,table) {
799
+ var c = table.config;
800
+ s = s.replace(/\-/g,"/");
801
+ if(c.dateFormat == "us") {
802
+ // reformat the string in ISO format
803
+ s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2");
804
+ } else if(c.dateFormat == "uk") {