MediaWiki:CargoSearch mtIYVmmQAOBizQ==.js

From Archon Arcana
Revision as of 17:57, 1 August 2020 by Saluk (talk | contribs) (javascript updated)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Note: After saving, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Go to Menu → Settings (Opera → Preferences on a Mac) and then to Privacy & security → Clear browsing data → Cached images and files.
// <HASH_ME>
var houses = ['Brobnar','Dis','Logos','Mars','Sanctum','Saurian','Star_Alliance','Shadows','Untamed','Anomaly']
var set5houses = ['Logos','Sanctum','Saurian','Star_Alliance','Shadows','Unfathomable','Untamed']
var sets = ['Call_of_the_Archons', 'Age_of_Ascension', 'Worlds_Collide', 'Mass_Mutation']
var types = ['Creature', 'Artifact', 'Upgrade', 'Action']
var rarities = ['Common', 'Uncommon', 'Rare', 'Fixed', 'Variant', 'Special']
var set5rarities = ['Common', 'Uncommon', 'Rare', 'Fixed', 'Variant', 'Special', 'Evil Twin']
var traits = ['Agent', 'Martian', 'AI', 'Beast', 'Scientist', 'Alien', 'Handuhan', 'Human', 'Robot', 'Krxix', 'Proximan', 'Thief', 'Ally', 'Angel', 'Spirit', 'Aquan', 'Cat', 'Cyborg', 'Insect', 'Leader', 'Witch', 'Mutant', 'Niffle', 'Rat', 'Wolf', 'Pirate', 'Demon', 'Knight', 'Sin', 'Dinosaur', 'Assassin', 'Egg', 'Philosopher', 'Politician', 'Priest', 'Soldier', 'Dragon', 'Psion', 'Elf']
var set5traits = ['AI', 'Beast', 'Alien', 'Scientist', 'Angel', 'Aquan', 'Thief', 'Fisher', 'Witch', 'Dinosaur', 'Politician', 'Elf', 'Human', 'Knight', 'Mutant', 'Power', 'Robot', 'Ship', 'Spirit']
var orders = {"Name":"Name","House":"House","Number":"CardNumber","Rarity":"Rarity","Power":"Power"}
var keywords = ['Alpha',
  'Assault',
  'Deploy',
  'Elusive',
  'Hazardous',
  'Invulnerable',
  'Omega',
  'Poison',
  'Skirmish',
  'Taunt']
var features = ['gigantic', 'errata']
var artists = ['Adam Schumpert', 'Adam Vehige', 'Agri Karuniawan', 'Albert Bruun', 'Alena Medovnikova', 'Alena Zhukova', 'Alexandre Leoni', 'Alexey Iavtuschenco', 'Allon Kremer', 'Alyn Spiller', 'Ameen Naksewee', 'Andreas Zafiratos', 'Andrew Bosley', 'Angelica Alieva', 'Angelina Chernyak', 'Anton Zemskov', 'Anzka Nguyen', 'Art tavern', 'Asep Ariyanto', 'Atha Kanaani', 'Ângelo Bortolini', 'BalanceSheet', 'Bogdan Tauciuc', 'Brandon Hunt', 'Brolken', 'Caio Monteiro', 'Caravan Studio', 'Chris Bjors', 'Cindy Avelino', 'Colin Searle', 'Dany Orizio', 'David Auden Nash', 'David Keen', 'David Kegg', 'David Pursley', 'David Tenorio', 'Diego Machuca', 'Djib', 'Dong Cheng', 'Eric Kenji Aoyagi', 'Etienne Hebinger', 'Fábio Perez', 'Felipe Martini', 'Forrest Imel', 'Francisco Badilla', 'Gabriel Rubio', 'Gabriel Scavariello', 'Gabriel Zanini', 'Gabriela Marchioro', 'Girma Moges']
var set5artists = ['Alexander Leoni', 'Alexandre Leoni', 'Art Tavern', 'Ângelo Bortolini', 'BalanceSheet', 'Bogdan Tauciuc', 'Brian Fajardo', 'Brolken', 'Caio Monteiro', 'Chris Bjors', 'David Tenorio', 'Dong Cheng', 'John Silva', 'Marc Escachx', 'Mariana Ennes', 'Michele Giorgi', 'Monztre', 'Radial Studio', 'Radial Studios', 'Roman Semenenko', 'Stanislav Dikolenko', 'Tomek Larek', 'Vladimir Kafanov', 'Vladimir Zyrianov']
var ambercounts = ['0', '1', '2', '3', '4+']
var armorcounts = ['0', '1', '2', '3', '4', '5+']
var powercounts = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10+']
var enhancecounts = ['1', '2', '3', '4', '5+']

var check_images = {
	'Brobnar': 'https://archonarcana.com/images/e/e0/Brobnar.png',
	'Dis': 'https://archonarcana.com/images/e/e8/Dis.png',
	'Logos': 'https://archonarcana.com/images/c/ce/Logos.png',
	'Mars': 'https://archonarcana.com/images/d/de/Mars.png',
	'Sanctum': 'https://archonarcana.com/images/c/c7/Sanctum.png',
	'Saurian': 'https://archonarcana.com/images/9/9e/Saurian_P.png',
	'Star_Alliance': 'https://archonarcana.com/images/7/7d/Star_Alliance.png',
	'Shadows': 'https://archonarcana.com/images/e/ee/Shadows.png',
	'Untamed': 'https://archonarcana.com/images/b/bd/Untamed.png',
  'Anomaly': 'https://archonarcana.com/images/thumb/a/a1/Anomaly_icon.png/40px-Anomaly_icon.png',
  'Unfathomable': 'https://archonarcana.com/images/1/10/Unfathomable.png'
}

class EditField {
  constructor(type, field, props) {
    this.type = type
    this.field = field
    this.label = ''
    this.split_on = ''
    this.values = []
    this.checknumbers = false
    this.divclass = ''
    this.attach = ''
    this.combo = false
    this.basic = false
    this.triggerAdvanced = false
    this.hidden = false
    Object.assign(this, props)
    return this
  }
  getElement() {
    return this.getElements()[0]
  }
  getElements() {
    if(this.type === 'int') {
      return [$('[name='+this.field+'_min')[0], $('[name='+this.field+'_max')[0]]
    }
    return $('[name='+this.field+']')
  }
  addElement() {
    var self=this
    var form=self.attach
    var presetValue = parseQueryString(this.field)
    if(presetValue && !this.basic){
      this.triggerAdvanced = true
    }
    if(form === '') {
      return
    }
    if (this.type === 'br') {
      $(form).append('<br>')
    }
    if (this.type === 'text') {
      if(this.label && !this.hidden){
        $(form).append('<label for="' + this.field + '">' + this.label + '</label>')
      }
      var h = ""
      if(this.hidden){
        h = ' type="hidden" '
      }
      $(form).append('<input name="' + this.field + '"'+h+' value="' + presetValue + '" />')
      console.log("add text field "+this.field)
    }
    if (this.type === 'select') {
      var options = []
      if(this.label) {
        options.push('<label for="' + this.field + '">' + this.label + '</label>')
      }
      if(this.combo) {
        options.push('<select class="js-multiple" name="'+this.field+'" multiple>')
      } else {
        options.push('<select name="'+this.field+'">')
      }
      if(!this.combo){
        options.push('<option value=""></option>')
      }
      this.values.map(function(option) {
        var is_checked = ''
        if (presetValue.match(option)) {
          is_checked = ' selected="true"'
        }
        options.push('<option value="'+option+'"'+is_checked+'>'+option+'</option>')
      })
      options.push('</select>')
      $(form).append(options.join(''))

      if(this.combo) {
        var el = $('select[name="'+this.field+'"]')
        console.log("Make combo field for "+this.field)
        console.log(el)
        el.select2()
        // Sort by last item added
        el.on("select2:select", function (evt) {
          var element = evt.params.data.element
          var $element = $(element)
          
          $element.detach()
          $(this).append($element)
          $(this).trigger("change")
        })
        presetValue.split('+').map(function(option) {
          var optionEl = $(el).find('[value="Name"]')
          optionEl.detach()
          $(el).append(optionEl)
        })
        $(el).trigger("change")
      }

    }
    if (this.type === 'checkbox') {
      //$(form).append('<span>' + this.label + ': </span>')
      this.values.map(function(value) {
        var img = check_images[value]
        var txt = ''
        txt += '<div class="'+self.divclass+'">'
        // Input
        txt += '<input type="checkbox" '
        if(img){
          txt += 'class="checkbox-house"'
        }
        if(presetValue.replace(/\+/g,' ').match(value)) {
          txt += ' checked="true" '
        }
        txt += 'name="'+self.field+'" id="'+value+'" value="'+value+'">' 
        // Label
        txt += '<label class="checkbox-label" for="'+value+'"><span class="checkbox-custom">'
        if(img){
          txt += '<span class="checkbox-checkbox"></span>'
          txt += '<img src="'+img+'" class="houseIcon">'
        } else {
          txt += value.replace(/\_/g, ' ')
        }
        txt += '</span></label></div>'
        $(form).append(txt)
      })
    }
  }
  getData() {
    if(this.type === 'text') {
      var val = this.getElement().value
      val = like_query(val)
      if(this.split_on.length>0) {
        return val.split(this.split_on)
      }
      return [val]
    } else if(this.type === 'select') {
      var vals = []
      console.log(this.getElement())
      if(!this.getElement().selectedOptions) {
        console.log('nothing selected for '+this.field)
        return vals
      }
      var opts = this.getElement().selectedOptions
      for(var i=0; i<opts.length; i++) {
        vals.push(opts[i].value)
      }
      return vals
    }
    else if(this.type === 'int') {
      return {
        min: this.getElements()[0].value,
        max: this.getElements()[1].value
      }
    }
    else if(this.type === 'checkbox') {
      var li = []
      var el = this.getElements()
      var self=this
      el.map(function(i) {
        if(el[i].checked) {
          var val = el[i].value
          if(self.checknumbers) {
            if(val==='0') {
              li.push('')
              li.push(val)
            }
          } else {
            li.push(val)
          }
        }
      })
      return li
    }
    return undefined
  }
  assignData(ob) {
    var d = this.getData()
    if(d!==undefined) {
      ob[this.field] = d
    }
  }
  listener(callback, search) {
    var event = function() {
      callback(search)
    }
    if(this.type === 'text'){
      this.getElement().addEventListener('input', event)
    } else if(this.type === 'checkbox') {
      var el = this.getElements()
      el.map(function(i) {
        el[i].addEventListener('change', event)
      })
    } else if(this.type === 'int') {
      this.getElements()[0].addEventListener('input', event)
      this.getElements()[1].addEventListener('input', event)
    } else if(this.type === 'select') {
      if(this.combo){
        return $('select[name="'+this.field+'"]').select2().on('change', event)
      }
      this.getElement().addEventListener('change', event)
    }
  }
}

var minmax = function(array, field, attach, values, hidemax=false, min_label="Min ") {
  array.push(new EditField('select', field+'_min', {'label':min_label,'attach':attach, 'values':values}))
  if(!hidemax) {
    array.push(new EditField('select', field+'_max', {'label':'Max ','attach':attach, 'values':values}))
  }
}

var searchFields = [
  new EditField('checkbox', 'houses', 
    {'label':'Houses', 'basic':true, 
     'values':houses, 'divclass':'house', 'attach':"div.house-entries"}), 
  new EditField('text', 'cardname', {'attach':'div.card-name-entries', 'split_on': '|', 'basic':true}),
  new EditField('checkbox', 'sets', 
    {'label':'Sets', 'basic':true,
     'values':sets, 'divclass':'set', 'attach':'div.set-entries'}), 
  new EditField('checkbox', 'types', 
    {'label':'Types', 'basic':true,
     'values':types, 'divclass':'type', 'attach':'div.type-entries'}), 
  new EditField('text', 'cardtext', {'attach':'div.card-text-entries', 'split_on': '|'}),
  new EditField('text', 'flavortext', {'attach':'div.flavor-text-entries', 'split_on': '|'}),
  new EditField('text', 'cardnumber', {'attach':'div.card-number-entries'}),
  new EditField('select', 'rarities', 
    {'values':rarities, 'basic':true,
     'combo': true, 'attach':'div.rarity-entries'}), 
  new EditField('select', 'traits', 
    {'values':traits, 'combo':true, 'attach':'div.trait-entries'}),
  new EditField('select', 'artists', 
    {'values':artists, 'combo': true, 'attach': 'div.artist-entries'}),
  new EditField('select', 'cardkeywords', 
    {'values':keywords, 'combo': true, 'attach': 'div.keyword-entries'}),
  new EditField('select', 'order_by',
    {'attach':'div.order-entries', 'combo':true,
    'values':Object.keys(orders)})
  /*new EditField('text', 'errata', 
    {'hidden':true, 'attach':'div.card-text-entries'}),
  new EditField('text', 'gigantic', 
    {'hidden':true, 'attach':'div.card-text-entries'}),*/
  /*new EditField('text', 'exclusiveSet', 
  {'hidden':true, 'attach':'div.card-text-entries'}),*/
]
minmax(searchFields, 'amber', 'div.aember-entries', ambercounts)
minmax(searchFields, 'armor', 'div.armor-entries', armorcounts)
minmax(searchFields, 'power', 'div.power-entries', powercounts)
minmax(searchFields, 'enhance_amber', 'div.enhance-entries', enhancecounts, hidemax=true, min_label='<img src="https://archonarcana.com/images/f/fb/Enhance_aember.png" width="20px" class="enhance-image">')
minmax(searchFields, 'enhance_capture', 'div.enhance-entries', enhancecounts, hidemax=true, min_label='<img src="https://archonarcana.com/images/f/fc/Enhance_capture.png" width="20px" class="enhance-image">')
minmax(searchFields, 'enhance_damage', 'div.enhance-entries', enhancecounts, hidemax=true, min_label='<p></p><img src="https://archonarcana.com/images/5/50/Enhance_damage.png" width="20px" class="enhance-image">')
minmax(searchFields, 'enhance_draw', 'div.enhance-entries', enhancecounts, hidemax=true, min_label='<img src="https://archonarcana.com/images/a/ac/Enhance_draw.png" width="20px" class="enhance-image">')

var getSearchField = function(field) {
  var foundField = null
  searchFields.map(function(searchField) {
    if(searchField.field===field) {
      foundField = searchField
      return
    }
  })
  return foundField
}

var parseQueryString = function (argument) {
  var res = '[\\?&]' + argument + '=([^&#]*)'
  var found = new RegExp(res).exec(window.location.href)
  if (found) {
    return decodeURIComponent(found[1])
  } else {
    return ''
  }
}

function htmlDecode(input){
  var e = document.createElement('div')
  e.innerHTML = input
  return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue
}

function isElementInViewport (el) {

  // Special bonus for those using jQuery
  if (typeof jQuery === "function" && el instanceof jQuery) {
      el = el[0];
  }

  var rect = el.getBoundingClientRect();

  return (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /* or $(window).height() */
      rect.right <= (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */
  );
}

var joined = function (pre, ar, post, logic, filter=function(x){return x}) {
  if (ar.length > 0) {
    var nar = ar.filter(function (item) {
      return item
    })
    nar = nar.map(function (item) {
      return pre + filter(item.replace(/\_/g, '%20')) + post
    })
    if (nar.length > 0) {
      return '(' + nar.join('%20' + logic + '%20') + ')'
    }
  }
  return ''
}

var statQuery = function(card_db, clauses, statInput, field) {
  if(statInput) {
    console.log(statInput)
    if(statInput.min===undefined || statInput.max===undefined){
      return
    }
    if(statInput.min.length>0 | statInput.max.length>0) {
      var min = statInput.min
      min = min.replace('+', '')
      if (!min) {
        min = 0
      }
      var max = statInput.max
      if (!max||max.search(/\+/)>=0) {
        max = 5000
      }
      clauses.push(
        joined('', [
          card_db+'.'+field+' >= ' + min,
          card_db+'.'+field+' <= ' + max
        ], '%20', 'AND')
      )
    }
  }
  return
}

var unhashImage = function(imgName) {
  var hash = md5(imgName)
  var firsthex = hash.substring(0,1)
  var first2 = hash.substring(0,2)
  return '/images/'+firsthex+'/'+first2+'/'+imgName
}

var unhashThumbImage = function(imgName) {
  return 'https://archonarcana.com/thumb.php?f='+imgName+'&width=200'
  var hash = md5(imgName)
  var firsthex = hash.substring(0,1)
  var first2 = hash.substring(0,2)
  return '/images/thumb/'+firsthex+'/'+first2+'/'+imgName+'/200px-'+imgName
}

var loadImage = function(image) {
  image.setAttribute('src', image.getAttribute('data-src'))
  image.onload = () => {
    image.removeAttribute('data-src')
  }
}

var padnum = function(number){
  if(number.length>=3){
    return number
  }
  var num_string = '000'+number
  return num_string.substring(num_string.length-3,num_string.length)
}

var like_query = function(s){
  return s.replace('"', '%').replace("'", '%')
}

var CSearch = {
  element: undefined,
  offset: 0,
  offsetActual: 0,
  names_used: new Set(),
  pageSize: 20,
  totalCount: 0,
  houses: [],
  types: [],
  sets: [],
  cardname: [],
  cardtext: [],
  flavortext: [],
  power_min: [""],
  power_max: [""],
  amber_min: [""],
  amber_max: [""],
  armor_min: [""],
  armor_max: [""],
  enhance_amber_min: [""],
  enhance_amber_max: [""],
  enhance_damage_min: [""],
  enhance_damage_max: [""],
  enhance_capture_min: [""],
  enhance_capture_max: [""],
  enhance_draw_min: [""],
  enhance_draw_max: [""],
  rarities: [],
  traits: [],
  artists: [],
  cardkeywords: [],
  cardnumber: [],
  order_by: [],
  errata: [false],
  gigantic: [false],
  exclusiveSet: [false],
  spoilers: false,
  loadingCards: false,
  loadingCount: false,
  requestcount: 0,
  output_settings: {
    img_width: 200,
    img_height: 280
  },
  init: function (element, pageSize) {
    var self=this
    this.offset = 0
    this.offsetActual = 0
    this.pageSize = Number.parseInt(pageSize)
    this.element = element;
    this.spoilers = this.element.attr('data-spoilers')!=null;
    if(this.spoilers){
      getSearchField('houses').values = set5houses
      getSearchField('rarities').values = set5rarities
      getSearchField('traits').values = set5traits
      getSearchField('artists').values = set5artists
      searchFields = searchFields.filter(function(field) {
        if(field.field==='sets'){
          return false
        }
        return true
      })
    }
    window.addEventListener("scroll", function() {
      self.listenScroll()
    })
  },
  toUrl: function() {
    var elements = []
    var self = this
    searchFields.forEach(function (searchField) {
      var val = self[searchField.field]
      val = val.join('+')
      if(val) {
        elements.push(searchField.field+'='+val)
      }
    })
    elements = elements.join('&')
    if(elements){
      elements = '?'+elements
    }
    var root_url = '/Card_Gallery'
    if(this.spoilers){
      root_url = '/Spoilers'
    }
    history.replaceState({}, document.title, root_url+elements)
  },
  initForm: function(self) {
    searchFields.map(function(field) {
      field.assignData(self)
    })
    if (self.order_by.length==0){
      if(!self.spoilers){
        self.order_by = ['House', 'Name']
      } else {
        self.order_by = ['Number']
      }
    }
    self.offset = 0
    self.offsetActual = 0
    self.toUrl()
    self.newSearch()
  },
  initElement: function(self) {
    s = this.element.attr('data-search')
    s.split(';').forEach((k)=>{
      var kv = k.split(':')
      this[kv[0]] = kv[1].split(' or ')
    })
    s = this.element.attr('data-output')
    s.split(';').forEach((k)=>{
      var kv = k.split(':')
      this.output_settings[kv[0]] = kv[1]
    })
    self.newSearch()
  },
  newSearch: function() {
    var self=this
    self.names_used = new Set()
    self.offset = 0
    self.offsetActual = 0
    if(self.loadingCount) self.loadingCount.abort()
    if(self.loadingCards) self.loadingCards.abort()
    self.requestcount ++
    self.element.empty()
    self.loadCount();
    self.load();
  },
  searchString: function (returnType) {
    var traits = []
    this.traits.forEach(function(trait) {
      traits.push('=%22'+trait+'%22')
      traits.push('%20LIKE%20%22%25+•+'+trait+'%22')
      traits.push('%20LIKE%20%22'+trait+'+•+%25%22')
      traits.push('%20LIKE%20%22%25+•+'+trait+'+•+%25%22')
    })
    var keywordsToSearch = []
    console.log(this.cardkeywords)
    this.cardkeywords.forEach(function(keyword) {
      keywordsToSearch.push('=%22'+keyword+'%22')
      keywordsToSearch.push('%20LIKE%20%22%25+•+'+keyword+'%22')
      keywordsToSearch.push('%20LIKE%20%22'+keyword+'+•+%25%22')
      keywordsToSearch.push('%20LIKE%20%22%25+•+'+keyword+'+•+%25%22')
    })
    console.log(this.cardkeywords)
    var housesToSearch = []
    this.houses.forEach(function(house) {
      housesToSearch.push('=%22'+house+'%22')
      housesToSearch.push('%20LIKE%20%22%25+•+'+house+'%22')
      housesToSearch.push('%20LIKE%20%22'+house+'+•+%25%22')
      housesToSearch.push('%20LIKE%20%22%25+•+'+house+'+•+%25%22')
    })
    if(this.gigantic[0]) {
      this.cardtext = ["other half"]
    }
    var card_db = 'CardData'
    var join_sets = true
    if(this.spoilers){
      card_db = 'SpoilerData'
      join_sets = false
    }
    var clauses = [joined(card_db+'.House', housesToSearch, '', 'OR'),
      joined('Type=%22', this.types, '%22', 'OR'),
      //joined('SetName=%22', this.sets, '%22', 'OR'),
      joined('Rarity=%22', this.rarities, '%22', 'OR'),
      joined(card_db+'.Name%20LIKE%20%22%25', this.cardname, '%25%22', 'OR'),
      joined(card_db+'.Artist=%22', this.artists, '%22', 'OR'),
      joined(card_db+'.Traits', traits, '', 'OR'),
      joined(card_db+'.Keywords', keywordsToSearch, '', 'OR'),
      joined(card_db+'.SearchFlavorText%20LIKE%20%22%25', this.flavortext, '%25%22', 'OR'),
      joined(card_db+'.SearchText%20LIKE%20%22%25', this.cardtext, '%25%22', 'OR'),
      joined('CardNumber=%22', this.cardnumber, '%22', 'OR', padnum)
    ]
    if(!this.exclusiveSet[0]) {
      clauses.push(joined('SetName=%22', this.sets, '%22', 'OR'))
    }
    statQuery(card_db, clauses, {'min':this.power_min[0], 'max':this.power_max[0]}, 'Power')
    statQuery(card_db, clauses, {'min':this.amber_min[0], 'max':this.amber_max[0]}, 'Amber')
    statQuery(card_db, clauses, {'min':this.armor_min[0], 'max':this.armor_max[0]}, 'Armor')
    statQuery(card_db, clauses, {'min':this.enhance_amber_min[0], 'max':this.enhance_amber_min[0]}, 'EnhanceAmber')
    statQuery(card_db, clauses, {'min':this.enhance_draw_min[0], 'max':this.enhance_draw_min[0]}, 'EnhanceDraw')
    statQuery(card_db, clauses, {'min':this.enhance_capture_min[0], 'max':this.enhance_capture_min[0]}, 'EnhanceCapture')
    statQuery(card_db, clauses, {'min':this.enhance_damage_min[0], 'max':this.enhance_damage_min[0]}, 'EnhanceDamage')
    if(this.errata[0]){
      clauses.push('ErrataData.Version IS NOT NULL')
    }
    var where = joined('', clauses,
      '', 'AND')
    where = '&where=' + where
    var fields_array = [card_db+'.Power', card_db+'.Rarity', card_db+'.Name', card_db+'.House', card_db+'.Type', card_db+'.Image']
    if(join_sets){
      fields_array.push('SetData.CardNumber')
    }
    if(!this.spoilers){
      fields_array.push(card_db+'.Text')
    }
    if(this.spoilers){
      fields_array.push(card_db+'.CardNumber')
      fields_array.push(card_db+'.SearchText')
      fields_array.push(card_db+'.SearchFlavorText')
      fields_array.push(card_db+'.Traits')
      fields_array.push(card_db+'.Armor')
      fields_array.push(card_db+'.IsNew')
      fields_array.push(card_db+'.Source')
      fields_array.push(card_db+'.Amber')
    }
    var fieldstring = fields_array.join('%2C')
    var fields = '&fields=' + fieldstring
    var start = '/api.php?action=cargoquery&format=json'
    var tables = '&tables='+card_db
    if(join_sets) {
      tables += '%2C%20SetData'
    }
    var countFields = '&fields=COUNT(DISTINCT%20'+card_db+'.Name)'
    var groupby = '&group_by=' + fieldstring
    var joinon = ''
    if(join_sets){
      var joinon = '&join_on='+card_db+'._pageName=SetData._pageName'
    }
    var limitq = '&limit=' + this.pageSize * sets.length
    var offsetq = '&offset=' + this.offset
    var order_by = '&order_by=' + this.order_by.map(function(order){
      return orders[order]
    }).join('%2C')
    var having = ''
    if(this.errata[0]) {
      tables += '%2C%20ErrataData'
      joinon += ','+card_db+'._pageName=ErrataData._pageName'
    }
    if(this.exclusiveSet[0]) {
      console.log('is exclusive')
      var each_set = []
      this.sets.map((set)=>{
        console.log('check search set'+set)
        var this_set = []
          for(const prevSet of sets){
            console.log('prevset:'+prevSet)
            if(prevSet===set){
              break
            }
            this_set.push('sum(SetData.SetName="'+prevSet.replace(/\_/g, ' ')+'")=0')
          }
        console.log(this_set)
        each_set.push(joined('',this_set,'','AND'))
      })
      console.log(each_set)
      having = '&having='+joined('',each_set,'','OR')
    }
    console.log("having="+having)
    if (returnType === 'data') {
      q = start + tables + fields + where + joinon + groupby + limitq + offsetq + having + order_by
    } else if (returnType === 'count') {
      q = start + tables + countFields + where + joinon + '&limit=1' + having
    }
    console.log(q)
    return q
  },
  outputImageResult(self,cardData) {
    var el = ''
    el += '<div class="gallery-image" style="position:relative;text-align:center">'
    el += ' <a href="/' + cardData.Name + '">'
    var imgurl = '/Special:Redirect/file/' + cardData.Image
    //el += '<img width=180 src="https://archonarcana.com/index.php?title=Special:Redirect/file/' + card.title.Image + '&width=200">'
    el += '<img id="img_'+cardData.Name.replace(/\(|\)/g,'br')+'" width='+self.output_settings.img_width+' height='+self.output_settings.img_height+' src="'+unhashThumbImage(cardData.Image)+'" data-src="'+unhashImage(cardData.Image)+'">'
    el += '<div style="position:absolute;bottom:8px;left:16px;">'+cardData.Name+'</div>'
    // Card number
    // el += '<div style="position:absolute;bottom:8px;left:60px;background-color:white">'+card.title.CardNumber+'</div>'
    el += '</a>'
    el += '</div>'
    return el
  },
  outputSpoilerResult(self,cardData) {
    var thumbsrc = unhashThumbImage(cardData.Image)
    var fullsrc = unhashImage(cardData.Image)

    var el = '<div class="spoilerEntry spoilerReprint">'
    if(cardData.IsNew==='yes'){
      el='<div class="spoilerEntry">'
      el+='<div class="newCard">new</div>'
    }
    el += '<div class="image"><div class="header">'
    el += '<div class="number">NUMBER</div>'
    el += '<div class="name">'
    el += 'NAME'
    el += '</div></div>'
    el += '<div class="picture"><center><div class="center"><div class="floatnone"><a href="/File:IMAGE" class="image"><img alt="IMAGEALT" src="IMAGESRC" decoding="async" style="vertical-align: middle" width="225" height="320" data-src="IMAGEFULL"></a></div></div></center></div></div>'
    el += '<div class="text"><div class="header"><div class="number">NUMBER</div><div class="name">'
    el += 'NAME'
    el += '</div></div>'
    el += '<div class="cardInfo">'
    if(cardData.Power!= "" || cardData.Armor!=""){
      el += ' POWER power - ARMOR armor '
    }
    if(cardData.Amber!=""){
      el += ' AMBER <img src="https://archonarcana.com/images/f/fb/Enhance_aember.png" width="18px"> '
    }
    if(cardData.Power!= "" || cardData.Armor!="" || cardData.Amber){
      el += '<br>'
    }
    el += '<i>TRAITS</i><p>'
    el += 'TEXT<p><small><b>Source: </b><i>SOURCE</i></small></div>'
    el += '<div class="bottomRow"><div class="type">TYPE</div><div class="rarity">RARITY</div>'
    el += '</div></div></div>'

    el += '<div class="mobileEntry">'
    if(cardData.IsNew==='yes'){
      el += '<div class="newCard">new</div>'
    }
    el += '<div class="header">\
      <div class="number">NUMBER</div><div class="name">NAME</div>\
      </div><div class="picture"><div class="floatnone">\
      <a href="/File:IMAGE" class="image">\
      <img alt="IMAGEALT" src="IMAGESRC" decoding="async" style="vertical-align: middle" width="225" height="320" data-src="IMAGEFULL"></img></a></div></div>\
      <div class="mobileText">'
    if(cardData.Power!= "" || cardData.Armor!=""){
      el += ' POWER power - ARMOR armor '
    }
    if(cardData.Amber!=""){
      el += ' AMBER <img src="https://archonarcana.com/images/f/fb/Enhance_aember.png" width="18px"> '
    }
    if(cardData.Power!= "" || cardData.Armor!="" || cardData.Amber){
      el += '<br>'
    }
    el += '<i>TRAITS</i><p>TEXT<p><small><b>Source: </b><i>SOURCE</i></small></div>\
      <div class="mobileBottomRow">\
        <div class="type"><b>Type</b>: TYPE</div>\
        <div class="rarity"><b>Rarity</b>: RARITY</div>\
      </div></div>'
    var evil_twin = ""
    if(cardData.Rarity==='Evil Twin') {
      evil_twin = '<img src="https://archonarcana.com/images/4/42/Evil-twin.png" width="20px">'
    }
    var name = htmlDecode(cardData.Name).replace("(Evil Twin)","")
    if(cardData.IsNew==='yes'){
      name = '<a href="/File:IMAGE">' + name + '</a>' + evil_twin
    } else {
      name = '<a href="/'+name+'">' + name + '</a>' + evil_twin
    }
    el = el.replace(/NAME/g,name)
    el = el.replace(/RARITY/g,htmlDecode(cardData.Rarity))
    el = el.replace(/IMAGESRC/g,thumbsrc)
    el = el.replace(/IMAGEFULL/g,fullsrc)
    el = el.replace(/IMAGE/g,htmlDecode(cardData.Image))
    el = el.replace(/NUMBER/g,htmlDecode(cardData.CardNumber))
    el = el.replace(/TEXT/g,htmlDecode(cardData.SearchText))
    el = el.replace(/TYPE/g,htmlDecode(cardData.Type))
    el = el.replace(/TRAITS/g,htmlDecode(cardData.Traits))
    el = el.replace(/POWER/g,htmlDecode(cardData.Power))
    el = el.replace(/ARMOR/g,htmlDecode(cardData.Armor))
    el = el.replace(/SOURCE/g,htmlDecode(cardData.Source))
    el = el.replace(/AMBER/g,htmlDecode(cardData.Amber))
    console.log(el)
    return el
  },
  updateResults: function (resultsArray) {
    var self = this
    // Delete results tab
    var resultsTab = this.element
    $('.loader').remove()
    $('.load_more').remove()
    var count_retrieved = self.pageSize
    // For each card in query
    for (var i in resultsArray) {
      self.offset = self.offset + 1
      var card = resultsArray[i]
      if (self.names_used.has(card.title.Name)){
        continue
      }
      self.offsetActual += 1
      if(!self.spoilers) {
        resultsTab.append(self.outputImageResult(self,card.title))
      } else {
        resultsTab.append(self.outputSpoilerResult(self,card.title))
      }
      self.names_used.add(card.title.Name)
      count_retrieved -= 1
      if(count_retrieved<=0){
        break
      }
    }
    resultsTab.append('<div class="load_more"></div>')
    var imgs = $('img[data-src]')
    imgs.map(function(i) {
      var self = imgs[i]
      self.onload = () => {
        $(self).next().remove()
        loadImage(self)
      }
    })
  },
  wikitext: function(title) {
    self.loadingWiki = $.ajax('/api.php?action=parse&format=json&text={{Spoiler Query}}&title='+title+'&contentmodel=wikitext',
      {
        success: function(data, status, xhr) {
          $('#popup').empty()
          $('#popup').append(data['parse']['text']['*'])
          self.loadingWiki = false
        }
      }
    )
  },
  load: function() {
    this.element.append('<div class="loader">Loading...</div>')
    var self = this
    self.loadingCards = $.ajax(this.searchString('data'),
      {
        success: function (data, status, xhr) {
          if(xhr.requestcount<self.requestcount) return
          self.updateResults(data.cargoquery)
          self.loadingCards = false
        }
      }
    )
    self.loadingCards.requestcount = self.requestcount
  },
  loadCount: function() {
    var self=this
    self.loadingCount = $.ajax(self.searchString('count'),
      {
        success: function (data, status, xhr) {
          if(xhr.requestcount<self.requestcount) return
          self.totalCount = Number.parseInt(data.cargoquery[0].title['Name)'])
          self.loadingCount = false
          $('.cg-results').empty().append(self.totalCount + ' results')
          // buildCargoPages(offset, totalCount, limit)
        }
      }
    )
    self.loadingCount.requestcount = self.requestcount
  },
  nextPage: function() {
    if(this.offsetActual  >= this.totalCount){
      return false;
    }
    this.load()
  },
  listenScroll: function() {
    var self=this
    if(self.loadingCards || self.loadingCount){
      return false
    }
    if(isElementInViewport($('.load_more'))){
      self.nextPage()
      return true
    }
    var height = document.documentElement.scrollHeight
    scrollOffset = document.documentElement.scrollTop + window.innerHeight;
    if (scrollOffset >= height) {
      self.nextPage()
    }
  }
}

var buildCardSearchForm = function(search) {
  //$('#viewcards_form').append('<form method="GET" id="searchForm"></form>')
  var triggerAdvanced = false;
  searchFields.map(function(field) {
    field.addElement()
    if(field.triggerAdvanced){
      triggerAdvanced = true
    }
  })
  $('.advanced-search')[0].addEventListener("click", function(evt) {
    var on = $('.cg-advanced-menu')[0].style.display !== 'none'
    if(on) {
      $('.cg-advanced-menu')[0].style = 'display:none;'
      $('.advanced-search-icon')[0].style = ''
    } else {
      $('.cg-advanced-menu')[0].style = ''
      $('.advanced-search-icon')[0].style = 'transform:rotate(180deg)'
    }
  })
  if(triggerAdvanced) {
    $('.advanced-search')[0].click()
  }
  searchFields.map(function(field) {
    field.listener(search.initForm, search)
  })
  console.log('form built')
}

var init_cargo_search = function () {
  console.log('initing cargo search')
  if ($('.card-gallery-images').length>0) {
    CSearch.init($('.card-gallery-images'), 50)
    buildCardSearchForm(CSearch)
    CSearch.initForm(CSearch)
  } else if($('.spoilerOuter').length>0) {
    CSearch.init($('.spoilerOuter'), 50)
    buildCardSearchForm(CSearch)
    CSearch.initForm(CSearch)
  }
  if ($('#cargo_results').length>0) {
    CSearch.init($('#cargo_results'), 20)
    CSearch.initElement(CSearch)
  }
}