<commit_before>WebpackServiceWorker(%data_var_name%);

function WebpackServiceWorker(params) {
  var strategy;
  var assets = params.assets;
  var tagMap = {
    all: params.version,
    changed: 'static',
    hash: params.hash
  };

  var CACHE_PREFIX = params.name;
  var CACHE_TAG = tagMap[strategy];
  var CACHE_NAME = CACHE_PREFIX + ':' + CACHE_TAG;

  var allAssets = [].concat(assets.main, assets.additional, assets.optional);

  self.addEventListener('install', function(event) {
    console.log('[SW]:', 'Install event');

    event.waitUntil(
      cacheAssets('main')
    );
  });

  self.addEventListener('activate', function(event) {
    console.log('[SW]:', 'Activate event');

    var caching;
    var deletion = deleteObsolete();

    if (assets.additional.length) {
      caching = strategy === 'changed' ?
        updateChanged() : cacheAssets('additional');
    } else {
      caching = Promise.resolve();
    }

    if (strategy === 'changed') {
      deletion = deletion;
    }

    event.waitUntil(Promise.all([caching, deletion]));
  });

  function cacheAssets(section) {
    return caches.open(CACHE_NAME).then(function(cache) {
      return cache.addAll(assets[section]).then(function() {
        console.groupCollapsed('[SW]:', 'Cached assets: ' + section);
        assets[section].forEach(function(asset) {
          console.log('Asset:', asset);
        });
        console.groupEnd();
      });
    })
  }

  function deleteObsolete() {
    return caches.keys().then(function(names) {
      return Promise.all(names.map(function(name) {
        if (name === CACHE_NAME || name.indexOf(CACHE_PREFIX) !== 0) return;
        console.log('[SW]:', 'Delete cache:', name);
        return caches.delete(name);
      }));
    });
  }

  function updateChanged() {
    var cache;

    return caches.open(CACHE_NAME).then(function(_cache) {
      cache = _cache;
      return _cache.keys();
    }).then(function(keys) {
      var diff = assets.additional.concat();
      var deletion = keys.map(function(req) {
        var url = new URL(req.url);

        if (allAssets.indexOf(url.pathname) === -1) {
          return cache.delete(req);
        }

        var index = diff.indexOf(url.pathname);

        if (index !== -1) {
          diff.splice(index, 1);
        }
      });

      var caching = cache.addAll(diff);

      return Promise.all([
        Promise.all(deletion),
        caching
      ]);
    });
  }

  self.addEventListener('fetch', function(event) {
    var url = new URL(event.request.url);

    if (
      url.origin !== location.origin ||
      allAssets.indexOf(url.pathname) === -1
    ) {
      if (DEBUG) {
        console.log('Path [' + url.pathname + '] does not match any assets');
      }

      return event.respondWith(
        fetch(event.request)
      );
    }

    var resource = caches.match(event.request).then(function(response) {
      if (response) {
        if (DEBUG) {
          console.log('Path [' + url.pathname + '] from cache');
        }

        return response;
      }

      return fetch(event.request.clone()).then(function(response) {
        if (
          !response || response.status !== 200 || response.type !== 'basic'
        ) {
          if (DEBUG) {
            console.log('Path [' + url.pathname + '] wrong response');
          }

          return response;
        }

        if (DEBUG) {
          console.log('Path [' + url.pathname + '] fetched');
        }

        var responseClone = response.clone();

        caches.open(CACHE_NAME).then(function(cache) {
          return cache.put(event.request, responseClone);
        }).then(function() {
          if (DEBUG) {
            console.log('Path [' + url.pathname + '] cached');
          }
        });

        return response;
      });
    })

    event.respondWith(resource);
  });
}<commit_msg>SW: skipWaiting on activate<commit_after>WebpackServiceWorker(%data_var_name%);

function WebpackServiceWorker(params) {
  var strategy;
  var assets = params.assets;
  var tagMap = {
    all: params.version,
    changed: 'static',
    hash: params.hash
  };

  var CACHE_PREFIX = params.name;
  var CACHE_TAG = tagMap[strategy];
  var CACHE_NAME = CACHE_PREFIX + ':' + CACHE_TAG;

  var allAssets = [].concat(assets.main, assets.additional, assets.optional);

  self.addEventListener('install', function(event) {
    console.log('[SW]:', 'Install event');

    event.waitUntil(
      cacheAssets('main')
    );
  });

  self.addEventListener('activate', function(event) {
    console.log('[SW]:', 'Activate event');

    var caching;
    var deletion = deleteObsolete();

    if (assets.additional.length) {
      caching = strategy === 'changed' ?
        updateChanged() : cacheAssets('additional');
    } else {
      caching = Promise.resolve();
    }

    if (strategy === 'changed') {
      deletion = deletion;
    }

    event.waitUntil(Promise.all([caching, deletion]).then(function() {
      if (self.skipWaiting) self.skipWaiting();
    }));
  });

  function cacheAssets(section) {
    return caches.open(CACHE_NAME).then(function(cache) {
      return cache.addAll(assets[section]).then(function() {
        console.groupCollapsed('[SW]:', 'Cached assets: ' + section);
        assets[section].forEach(function(asset) {
          console.log('Asset:', asset);
        });
        console.groupEnd();
      });
    })
  }

  function deleteObsolete() {
    return caches.keys().then(function(names) {
      return Promise.all(names.map(function(name) {
        if (name === CACHE_NAME || name.indexOf(CACHE_PREFIX) !== 0) return;
        console.log('[SW]:', 'Delete cache:', name);
        return caches.delete(name);
      }));
    });
  }

  function updateChanged() {
    var cache;

    return caches.open(CACHE_NAME).then(function(_cache) {
      cache = _cache;
      return _cache.keys();
    }).then(function(keys) {
      var diff = assets.additional.concat();
      var deletion = keys.map(function(req) {
        var url = new URL(req.url);

        if (allAssets.indexOf(url.pathname) === -1) {
          return cache.delete(req);
        }

        var index = diff.indexOf(url.pathname);

        if (index !== -1) {
          diff.splice(index, 1);
        }
      });

      var caching = cache.addAll(diff);

      return Promise.all([
        Promise.all(deletion),
        caching
      ]);
    });
  }

  self.addEventListener('fetch', function(event) {
    var url = new URL(event.request.url);

    if (
      url.origin !== location.origin ||
      allAssets.indexOf(url.pathname) === -1
    ) {
      if (DEBUG) {
        console.log('Path [' + url.pathname + '] does not match any assets');
      }

      return event.respondWith(
        fetch(event.request)
      );
    }

    var resource = caches.match(event.request).then(function(response) {
      if (response) {
        if (DEBUG) {
          console.log('Path [' + url.pathname + '] from cache');
        }

        return response;
      }

      return fetch(event.request.clone()).then(function(response) {
        if (
          !response || response.status !== 200 || response.type !== 'basic'
        ) {
          if (DEBUG) {
            console.log('Path [' + url.pathname + '] wrong response');
          }

          return response;
        }

        if (DEBUG) {
          console.log('Path [' + url.pathname + '] fetched');
        }

        var responseClone = response.clone();

        caches.open(CACHE_NAME).then(function(cache) {
          return cache.put(event.request, responseClone);
        }).then(function() {
          if (DEBUG) {
            console.log('Path [' + url.pathname + '] cached');
          }
        });

        return response;
      });
    })

    event.respondWith(resource);
  });
}<|endoftext|>


<commit_before>// $Id$
(function ($) {

Drupal.tableHeaderDoScroll = function () {
  if ($.isFunction(Drupal.tableHeaderOnScroll)) {
    Drupal.tableHeaderOnScroll();
  }
};

Drupal.behaviors.tableHeader = {
  attach: function (context, settings) {
    // This breaks in anything less than IE 7. Prevent it from running.
    if ($.browser.msie && parseInt($.browser.version, 10) < 7) {
      return;
    }

    // Keep track of all cloned table headers.
    var headers = [];

    $('table.sticky-enabled thead', context).once('tableheader', function () {
      // Clone the table header so it inherits original jQuery properties. Hide
      // the table to avoid a flash of the header clone upon page load.
      var headerClone = $(this).clone(true).hide().insertBefore(this.parentNode).wrap('

').parent().css({
        position: 'fixed',
        top: '0px'
      });

      headerClone = $(headerClone)[0];
      headers.push(headerClone);

      // Store parent table.
      var table = $(this).parent('table')[0];
      headerClone.table = table;
      // Finish initializing header positioning.
      tracker(headerClone);
      // We hid the header to avoid it showing up erroneously on page load;
      // we need to unhide it now so that it will show up when expected.
      $(headerClone).children('thead').show();

      $(table).addClass('sticky-table');
    });

    // Define the anchor holding var.
    var prevAnchor = '';

    // Track positioning and visibility.
    function tracker(e) {
      // Reset top position of sticky table headers to the current top offset.
      var topOffset = Drupal.settings.tableHeaderOffset ? eval(Drupal.settings.tableHeaderOffset + '()') : 0;
      $('.sticky-header').css('top', topOffset + 'px');
      // Save positioning data.
      var viewHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
      if (e.viewHeight != viewHeight) {
        e.viewHeight = viewHeight;
        e.vPosition = $(e.table).offset().top - 4 - topOffset;
        e.hPosition = $(e.table).offset().left;
        e.vLength = e.table.clientHeight - 100;
        // Resize header and its cell widths.
        var parentCell = $('th', e.table);
        $('th', e).each(function (index) {
          var cellWidth = parentCell.eq(index).css('width');
          // Exception for IE7.
          if (cellWidth == 'auto') {
            cellWidth = parentCell.get(index).clientWidth + 'px';
          }
          $(this).css('width', cellWidth);
        });
        $(e).css('width', $(e.table).css('width'));
      }

      // Track horizontal positioning relative to the viewport and set visibility.
      var hScroll = document.documentElement.scrollLeft || document.body.scrollLeft;
      var vOffset = (document.documentElement.scrollTop || document.body.scrollTop) - e.vPosition;
      var visState = (vOffset > 0 && vOffset < e.vLength) ? 'visible' : 'hidden';
      $(e).css({ left: -hScroll + e.hPosition + 'px', visibility: visState });

      // Check the previous anchor to see if we need to scroll to make room for the header.
      // Get the height of the header table and scroll up that amount.
      if (prevAnchor != location.hash) {
        if (location.hash != '') {
          var scrollLocation = $('td' + location.hash).offset().top - $(e).height();
          $('body, html').scrollTop(scrollLocation);
        }
        prevAnchor = location.hash;
      }
    }

    // Only attach to scrollbars once, even if Drupal.attachBehaviors is called
    //  multiple times.
    $('body').once(function () {
      $(window).scroll(Drupal.tableHeaderDoScroll);
      $(document.documentElement).scroll(Drupal.tableHeaderDoScroll);
    });

    // Track scrolling.
    Drupal.tableHeaderOnScroll = function () {
      $(headers).each(function () {
        tracker(this);
      });
    };

    // Track resizing.
    var time = null;
    var resize = function () {
      // Ensure minimum time between adjustments.
      if (time) {
        return;
      }
      time = setTimeout(function () {
        $('table.sticky-header').each(function () {
          // Force cell width calculation.
          this.viewHeight = 0;
          tracker(this);
        });
        // Reset timer.
        time = null;
      }, 250);
    };
    $(window).resize(resize);
  }
};

})(jQuery);
<commit_msg>- Patch #622550 by roborn: fixed block administration page table header sticking.<commit_after>// $Id$
(function ($) {

Drupal.tableHeaderDoScroll = function () {
  if ($.isFunction(Drupal.tableHeaderOnScroll)) {
    Drupal.tableHeaderOnScroll();
  }
};

Drupal.behaviors.tableHeader = {
  attach: function (context, settings) {
    // This breaks in anything less than IE 7. Prevent it from running.
    if ($.browser.msie && parseInt($.browser.version, 10) < 7) {
      return;
    }

    $('table.sticky-enabled thead', context).once('tableheader', function () {
      // Clone the table header so it inherits original jQuery properties. Hide
      // the table to avoid a flash of the header clone upon page load.
      var headerClone = $(this).clone(true).hide().insertBefore(this.parentNode).wrap('

').parent().css({
        position: 'fixed',
        top: '0px'
      });

      headerClone = $(headerClone)[0];

      // Store parent table.
      var table = $(this).parent('table')[0];
      headerClone.table = table;
      // Finish initializing header positioning.
      tracker(headerClone);
      // We hid the header to avoid it showing up erroneously on page load;
      // we need to unhide it now so that it will show up when expected.
      $(headerClone).children('thead').show();

      $(table).addClass('sticky-table');
    });

    // Define the anchor holding var.
    var prevAnchor = '';

    // Track positioning and visibility.
    function tracker(e) {
      // Reset top position of sticky table headers to the current top offset.
      var topOffset = Drupal.settings.tableHeaderOffset ? eval(Drupal.settings.tableHeaderOffset + '()') : 0;
      $('.sticky-header').css('top', topOffset + 'px');
      // Save positioning data.
      var viewHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
      if (e.viewHeight != viewHeight) {
        e.viewHeight = viewHeight;
        e.vPosition = $(e.table).offset().top - 4 - topOffset;
        e.hPosition = $(e.table).offset().left;
        e.vLength = e.table.clientHeight - 100;
        // Resize header and its cell widths.
        var parentCell = $('th', e.table);
        $('th', e).each(function (index) {
          var cellWidth = parentCell.eq(index).css('width');
          // Exception for IE7.
          if (cellWidth == 'auto') {
            cellWidth = parentCell.get(index).clientWidth + 'px';
          }
          $(this).css('width', cellWidth);
        });
        $(e).css('width', $(e.table).css('width'));
      }

      // Track horizontal positioning relative to the viewport and set visibility.
      var hScroll = document.documentElement.scrollLeft || document.body.scrollLeft;
      var vOffset = (document.documentElement.scrollTop || document.body.scrollTop) - e.vPosition;
      var visState = (vOffset > 0 && vOffset < e.vLength) ? 'visible' : 'hidden';
      $(e).css({ left: -hScroll + e.hPosition + 'px', visibility: visState });

      // Check the previous anchor to see if we need to scroll to make room for the header.
      // Get the height of the header table and scroll up that amount.
      if (prevAnchor != location.hash) {
        if (location.hash != '') {
          var scrollLocation = $('td' + location.hash).offset().top - $(e).height();
          $('body, html').scrollTop(scrollLocation);
        }
        prevAnchor = location.hash;
      }
    }

    // Only attach to scrollbars once, even if Drupal.attachBehaviors is called
    //  multiple times.
    $('body').once(function () {
      $(window).scroll(Drupal.tableHeaderDoScroll);
      $(document.documentElement).scroll(Drupal.tableHeaderDoScroll);
    });

    // Track scrolling.
    Drupal.tableHeaderOnScroll = function () {
      $('table.sticky-header').each(function () {
        tracker(this);
      });
    };

    // Track resizing.
    var time = null;
    var resize = function () {
      // Ensure minimum time between adjustments.
      if (time) {
        return;
      }
      time = setTimeout(function () {
        $('table.sticky-header').each(function () {
          // Force cell width calculation.
          this.viewHeight = 0;
          tracker(this);
        });
        // Reset timer.
        time = null;
      }, 250);
    };
    $(window).resize(resize);
  }
};

})(jQuery);
<|endoftext|>


<commit_before>/*
 *      This file is part of GPaste.
 *
 *      Copyright 2011-2013 Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
 *
 *      GPaste is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation, either version 3 of the License, or
 *      (at your option) any later version.
 *
 *      GPaste is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with GPaste.  If not, see <http://www.gnu.org/licenses/>.
 */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */

const Clutter = imports.gi.Clutter;
const Gettext = imports.gettext;
const GPaste = imports.gi.GPaste;
const Lang = imports.lang;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const Pango = imports.gi.Pango;
const PopupMenu = imports.ui.popupMenu;
const St = imports.gi.St;

const _ = Gettext.domain('GPaste').gettext;
const BUS_NAME = 'org.gnome.GPaste';
const OBJECT_PATH = '/org/gnome/GPaste';

const GPasteStatusIcon = new Lang.Class({
    Name: 'GPasteStatusIcon',
    Extends: St.BoxLayout,

    _init: function() {
        this.parent({ style_class: 'panel-status-menu-box' });

        this.add_child(new St.Icon({
            icon_name: 'edit-paste-symbolic',
            style_class: 'system-status-icon'
        }));

        this.add_child(new St.Label({
            text: '\u25BE',
            y_expand: true,
            y_align: Clutter.ActorAlign.CENTER
        }));
    }
});

const GPasteStateSwitch = new Lang.Class({
    Name: 'GPasteStateSwitch',
    Extends: PopupMenu.PopupSwitchMenuItem,

    _init: function(client) {
        this.parent(_("Track changes"), client.is_active());

        this._fromDaemon = false;

        client.connect('tracking', Lang.bind(this, function(c, state) {
            this._fromDaemon = true;
            this.setToggleState(state);
            this._fromDaemon = false;
        }));

        this.connect('toggled', Lang.bind(this, function() {
            if (!this._fromDaemon)
                client.track(this.state);
        }));
    }
});

const GPasteDeleteButton = new Lang.Class({
    Name: 'GPasteDeleteButton',
    Extends: St.Button,

    _init: function(client, index) {
        this.parent();

        this.child = new St.Icon({
            icon_name: 'edit-delete-symbolic',
            style_class: 'system-status-icon'
        });

        this.connect('clicked', function() {
            client.delete(index);
            return true;
        });

    }
});

const GPasteDeleteMenuItemPart = new Lang.Class({
    Name: 'GPasteDeleteMenuItemPart',
    Extends: St.Bin,

    _init: function(client, index) {
        this.parent({ x_align: St.Align.END });

        this.child = new GPasteDeleteButton(client, index);
    }
});

const GPasteMenuItem = new Lang.Class({
    Name: 'GPasteMenuItem',
    Extends: PopupMenu.PopupMenuItem,

    _init: function(client, index) {
        this.parent("");

        let text = this.label.clutter_text;
        text.max_length = 60;
        text.ellipsize = Pango.EllipsizeMode.END;

        this.connect('activate', function(actor, event) {
            client.select(index);
        });

        this.actor.connect('key-press-event', function(actor, event) {
            let symbol = event.get_key_symbol();
            if (symbol == Clutter.KEY_BackSpace || symbol == Clutter.KEY_Delete) {
                client.delete(index);
                return true;
            }
            return false;
        });

        this.actor.add(new GPasteDeleteMenuItemPart(client, index), { expand: true, x_align: St.Align.END });
    },

    setText: function(text) {
        this.label.set_text(text);
        this.actor.show();
    }
});

const GPasteDummyHistory = new Lang.Class({
    Name: 'GPasteDummyHistory',
    Extends: PopupMenu.PopupMenuItem,

    _init: function() {
        this.parent("");

        this.setSensitive(false);
    },

    update: function(error) {
        this.label.text = (error) ? _("(Couldn't connect to GPaste daemon)") : _("(Empty)");
    }
});

const GPasteHistoryWrapper = new Lang.Class({
    Name: 'GPasteHistoryWrapper',

    _init: function(client, menu, emptyHistoryItem) {
        this._history = [];

        for (let index = 0; index < 20; ++index) {
            let item = new GPasteMenuItem(client, index);
            this._history[index] = item;
            menu.addMenuItem(item);
        }

        this._history[0].label.set_style("font-weight: bold;");

        this._dummyHistory = new GPasteDummyHistory();

        menu.addMenuItem(this._dummyHistory);

        this._update(client, emptyHistoryItem);

        client.connect('changed', Lang.bind(this, function() {
            this._update(client, emptyHistoryItem);
        }));
    },

    _update: function(client, emptyHistoryItem) {
        let history = client.get_history();
        if (history != null && history.length != 0) {
            let limit = Math.min(history.length, this._history.length);
            for (let index = 0; index < limit; ++index)
                this._history[index].setText(history[index].replace(/\n/g, ' '));
            this._hideHistory(limit);
            this._dummyHistory.actor.hide();
            emptyHistoryItem.actor.show();
        } else {
            this._dummyHistory.update(history == null);
            this._hideHistory();
            emptyHistoryItem.actor.hide();
            this._dummyHistory.actor.show();
        }
    },

    _hideHistory: function(startIndex) {
        for (let index = startIndex || 0; index < this._history.length; ++index)
            this._history[index].actor.hide();
    }
});

const GPasteEmptyHistoryMenuItem = new Lang.Class({
    Name: 'GPasteEmptyHistoryMenuItem',
    Extends: PopupMenu.PopupMenuItem,

    _init: function(client) {
        this.parent(_("Empty history"));

        this.connect('activate', function() {
            client.empty();
        });
    }
});

const GPasteIndicator = new Lang.Class({
    Name: 'GPasteIndicator',
    Extends: PanelMenu.Button,

    _init: function() {
        this.parent(0.0, "GPaste");

        this.actor.add_child(new GPasteStatusIcon());

        this._client = new GPaste.Client();

        this.menu.addMenuItem(new GPasteStateSwitch(this._client));
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());

        let emptyHistoryItem = new GPasteEmptyHistoryMenuItem(this._client);

        this._history = new GPasteHistoryWrapper(this._client, this.menu, emptyHistoryItem);

        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this.menu.addMenuItem(emptyHistoryItem);
        this.menu.addSettingsAction(_("GPaste daemon settings"), 'gpaste-settings.desktop');

        this._client.connect('show-history', Lang.bind(this, function() {
            this.menu.open(true);
            this.menu._getMenuItems()[2].setActive(true);
        }));

        this._onStateChanged (true);
    },

    shutdown: funtion() {
        this._onStateChanged (false);
        this.destroy();
    }

    _onStateChanged: function (state) {
        this._client.on_extension_state_changed(state);
    }
});

function init(extension) {
    Gettext.bindtextdomain('gpaste', extension.metadata.localedir);
}

function enable() {
    Main.panel.addToStatusArea('gpaste', new GPasteIndicator());
}

function disable() {
    Main.panel.statusArea['gpaste'].shutDown();
}

<commit_msg>gnome-shell: little tweak<commit_after>/*
 *      This file is part of GPaste.
 *
 *      Copyright 2011-2013 Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
 *
 *      GPaste is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation, either version 3 of the License, or
 *      (at your option) any later version.
 *
 *      GPaste is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with GPaste.  If not, see <http://www.gnu.org/licenses/>.
 */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */

const Clutter = imports.gi.Clutter;
const Gettext = imports.gettext;
const GPaste = imports.gi.GPaste;
const Lang = imports.lang;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const Pango = imports.gi.Pango;
const PopupMenu = imports.ui.popupMenu;
const St = imports.gi.St;

const _ = Gettext.domain('GPaste').gettext;
const BUS_NAME = 'org.gnome.GPaste';
const OBJECT_PATH = '/org/gnome/GPaste';

const GPasteStatusIcon = new Lang.Class({
    Name: 'GPasteStatusIcon',
    Extends: St.BoxLayout,

    _init: function() {
        this.parent({ style_class: 'panel-status-menu-box' });

        this.add_child(new St.Icon({
            icon_name: 'edit-paste-symbolic',
            style_class: 'system-status-icon'
        }));

        this.add_child(new St.Label({
            text: '\u25BE',
            y_expand: true,
            y_align: Clutter.ActorAlign.CENTER
        }));
    }
});

const GPasteStateSwitch = new Lang.Class({
    Name: 'GPasteStateSwitch',
    Extends: PopupMenu.PopupSwitchMenuItem,

    _init: function(client) {
        this.parent(_("Track changes"), client.is_active());

        this._fromDaemon = false;

        client.connect('tracking', Lang.bind(this, function(c, state) {
            this._fromDaemon = true;
            this.setToggleState(state);
            this._fromDaemon = false;
        }));

        this.connect('toggled', Lang.bind(this, function() {
            if (!this._fromDaemon)
                client.track(this.state);
        }));
    }
});

const GPasteDeleteButton = new Lang.Class({
    Name: 'GPasteDeleteButton',
    Extends: St.Button,

    _init: function(client, index) {
        this.parent();

        this.child = new St.Icon({
            icon_name: 'edit-delete-symbolic',
            style_class: 'system-status-icon'
        });

        this.connect('clicked', function() {
            client.delete(index);
            return true;
        });

    }
});

const GPasteDeleteMenuItemPart = new Lang.Class({
    Name: 'GPasteDeleteMenuItemPart',
    Extends: St.Bin,

    _init: function(client, index) {
        this.parent({ x_align: St.Align.END });

        this.child = new GPasteDeleteButton(client, index);
    }
});

const GPasteMenuItem = new Lang.Class({
    Name: 'GPasteMenuItem',
    Extends: PopupMenu.PopupMenuItem,

    _init: function(client, index) {
        this.parent("");

        let text = this.label.clutter_text;
        text.max_length = 60;
        text.ellipsize = Pango.EllipsizeMode.END;

        this.connect('activate', function(actor, event) {
            client.select(index);
        });

        this.actor.connect('key-press-event', function(actor, event) {
            let symbol = event.get_key_symbol();
            if (symbol == Clutter.KEY_BackSpace || symbol == Clutter.KEY_Delete) {
                client.delete(index);
                return true;
            }
            return false;
        });

        this.actor.add(new GPasteDeleteMenuItemPart(client, index), { expand: true, x_align: St.Align.END });
    },

    setText: function(text) {
        this.label.set_text(text);
        this.actor.show();
    }
});

const GPasteDummyHistory = new Lang.Class({
    Name: 'GPasteDummyHistory',
    Extends: PopupMenu.PopupMenuItem,

    _init: function() {
        this.parent("");

        this.setSensitive(false);
    },

    update: function(error) {
        this.label.text = (error) ? _("(Couldn't connect to GPaste daemon)") : _("(Empty)");
    }
});

const GPasteHistoryWrapper = new Lang.Class({
    Name: 'GPasteHistoryWrapper',

    _init: function(client, menu, emptyHistoryItem) {
        this._history = [];

        for (let index = 0; index < 20; ++index) {
            let item = new GPasteMenuItem(client, index);
            this._history[index] = item;
            menu.addMenuItem(item);
        }

        this._history[0].label.set_style("font-weight: bold;");

        this._dummyHistory = new GPasteDummyHistory();

        menu.addMenuItem(this._dummyHistory);

        this._update(client, emptyHistoryItem);

        client.connect('changed', Lang.bind(this, function() {
            this._update(client, emptyHistoryItem);
        }));

        client.connect('show-history', function() {
            menu.open(true);
            menu._getMenuItems()[2].setActive(true);
        });

    },

    _update: function(client, emptyHistoryItem) {
        let history = client.get_history();
        if (history != null && history.length != 0) {
            let limit = Math.min(history.length, this._history.length);
            for (let index = 0; index < limit; ++index)
                this._history[index].setText(history[index].replace(/\n/g, ' '));
            this._hideHistory(limit);
            this._dummyHistory.actor.hide();
            emptyHistoryItem.actor.show();
        } else {
            this._dummyHistory.update(history == null);
            this._hideHistory();
            emptyHistoryItem.actor.hide();
            this._dummyHistory.actor.show();
        }
    },

    _hideHistory: function(startIndex) {
        for (let index = startIndex || 0; index < this._history.length; ++index)
            this._history[index].actor.hide();
    }
});

const GPasteEmptyHistoryMenuItem = new Lang.Class({
    Name: 'GPasteEmptyHistoryMenuItem',
    Extends: PopupMenu.PopupMenuItem,

    _init: function(client) {
        this.parent(_("Empty history"));

        this.connect('activate', function() {
            client.empty();
        });
    }
});

const GPasteIndicator = new Lang.Class({
    Name: 'GPasteIndicator',
    Extends: PanelMenu.Button,

    _init: function() {
        this.parent(0.0, "GPaste");

        this.actor.add_child(new GPasteStatusIcon());

        this._client = new GPaste.Client();

        this.menu.addMenuItem(new GPasteStateSwitch(this._client));
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());

        let emptyHistoryItem = new GPasteEmptyHistoryMenuItem(this._client);

        this._history = new GPasteHistoryWrapper(this._client, this.menu, emptyHistoryItem);

        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this.menu.addMenuItem(emptyHistoryItem);
        this.menu.addSettingsAction(_("GPaste daemon settings"), 'gpaste-settings.desktop');

        this._onStateChanged (true);
    },

    shutdown: funtion() {
        this._onStateChanged (false);
        this.destroy();
    }

    _onStateChanged: function (state) {
        this._client.on_extension_state_changed(state);
    }
});

function init(extension) {
    Gettext.bindtextdomain('gpaste', extension.metadata.localedir);
}

function enable() {
    Main.panel.addToStatusArea('gpaste', new GPasteIndicator());
}

function disable() {
    Main.panel.statusArea['gpaste'].shutDown();
}

<|endoftext|>


<commit_before>import {
  DocumentSchema, DocumentNode, InlineNode,
  XMLContainerNode, XMLElementNode, XMLTextElement
} from 'substance'
import { BOOLEAN, STRING, MANY, ONE, CHILDREN } from '../kit'
import { INTERNAL_BIBR_TYPES } from './ArticleConstants'
import InternalArticleDocument from './InternalArticleDocument'
// TODO: rename this to *Schema
import TextureArticleSchema from './TextureArticle'

/*
  TODO: we want to move away from a JATS oriented internal model.

  The internal model structures the data in different categories: content vs metadata.
  It is a challenge to define the boundary between these two categories.
  Here are some criteria:
  - Is the content displayed in a classical manuscript?
  - May the content contain citations, or references to other displayed elements?
*/

class Article extends XMLElementNode {}
Article.schema = {
  type: 'article',
  _childNodes: CHILDREN('metadata', 'content')
}

class ArticleRecord extends DocumentNode {}
ArticleRecord.schema = {
  type: 'article-record',
  volume: STRING,
  issue: STRING,
  fpage: STRING,
  lpage: STRING,
  pageRange: STRING,
  elocationId: STRING,
  acceptedDate: STRING,
  publishedDate: STRING,
  receivedDate: STRING,
  revReceivedDate: STRING,
  revRequestedDate: STRING
}

class TranslatableTextElement extends XMLTextElement {}
TranslatableTextElement.translations = CHILDREN('text-translation')

class TranslatableContainerElement extends XMLContainerNode {}
TranslatableTextElement.translations = CHILDREN('container-translation')

class Metadata extends XMLElementNode {}
Metadata.schema = {
  type: 'metadata',
  _childNodes: CHILDREN(
    'article-record', 'authors', 'editors', 'groups', 'organisations', 'awards', 'keywords', 'subjects'
  )
}

class Organisations extends XMLElementNode {}
Organisations.schema = {
  type: 'organisations',
  _childNodes: CHILDREN(...INTERNAL_BIBR_TYPES)
}

class Authors extends XMLElementNode {}
Authors.schema = {
  type: 'authors',
  _childNodes: CHILDREN('person')
}

class Editors extends XMLElementNode {}
Editors.schema = {
  type: 'editors',
  _childNodes: CHILDREN('person')
}

class Groups extends XMLElementNode {}
Groups.schema = {
  type: 'groups',
  _childNodes: CHILDREN('group')
}

class Awards extends XMLElementNode {}
Awards.schema = {
  type: 'awards',
  _childNodes: CHILDREN('award')
}

class Keywords extends XMLElementNode {}
Keywords.schema = {
  type: 'keywords',
  _childNodes: CHILDREN('award')
}

class Subjects extends XMLElementNode {}
Subjects.schema = {
  type: 'subjects',
  _childNodes: CHILDREN('award')
}

// TODO: as this node has a fixed layout, we might want to use a classical DocumentNode
// But this needs support for CSS select
class Content extends XMLElementNode {}
Content.schema = {
  type: 'content',
  _childNodes: CHILDREN('front', 'body', 'back')
}

class Front extends XMLElementNode {}
Front.schema = {
  type: 'front',
  _childNodes: CHILDREN('title', 'abstract')
}

class Back extends XMLElementNode {}
Back.schema = {
  type: 'back',
  _childNodes: CHILDREN('references', 'footnotes')
}

class Title extends TranslatableTextElement {}
Title.type = 'title'

class Abstract extends TranslatableContainerElement {}
Abstract.type = 'abstract'

class Heading extends XMLTextElement {}
Heading.type = 'heading'

class References extends XMLElementNode {}
References.schema = {
  type: 'references',
  _childNodes: CHILDREN(...INTERNAL_BIBR_TYPES)
}

class Footnotes extends XMLElementNode {}
Footnotes.schema = {
  type: 'footnotes',
  _childNodes: CHILDREN('fn')
}

// TODO: move all of this into InternalArticleSchema

class BibliographicEntry extends DocumentNode {}
BibliographicEntry.schema = {
  type: 'bibr'
}

class Book extends BibliographicEntry {}
Book.schema = {
  type: 'book',
  authors: CHILDREN('ref-contrib'),
  editors: CHILDREN('ref-contrib'),
  translators: CHILDREN('ref-contrib'),
  title: STRING,
  volume: STRING,
  edition: STRING,
  publisherLoc: STRING,
  publisherName: STRING,
  year: STRING,
  month: STRING,
  day: STRING,
  pageCount: STRING,
  series: STRING,
  doi: STRING,
  isbn: STRING,
  pmid: STRING
}

class Chapter extends BibliographicEntry {}
Chapter.schema = {
  type: 'chapter',
  title: STRING, // <chapter-title>
  containerTitle: STRING, // <source>
  volume: STRING,
  authors: CHILDREN('ref-contrib'), // <person-group person-group-type="author">
  editors: CHILDREN('ref-contrib'),
  translators: CHILDREN('ref-contrib'),
  edition: STRING,
  publisherLoc: STRING,
  publisherName: STRING,
  year: STRING,
  month: STRING,
  day: STRING,
  fpage: STRING,
  lpage: STRING,
  pageRange: STRING,
  elocationId: STRING,
  series: STRING,
  doi: STRING, // <pub-id pub-id-type="doi">
  isbn: STRING, // <pub-id pub-id-type="isbn">
  pmid: STRING // <pub-id pub-id-type="pmid">
}

class ConferencePaper extends BibliographicEntry {}
ConferencePaper.schema = {
  type: 'conference-paper',
  title: STRING, // <article-title>
  authors: CHILDREN('ref-contrib'),
  confName: STRING,
  confLoc: STRING,
  containerTitle: STRING, // <source>
  year: STRING,
  month: STRING,
  day: STRING,
  fpage: STRING,
  lpage: STRING,
  pageRange: STRING,
  elocationId: STRING,
  doi: STRING
}

class DataPublication extends BibliographicEntry {}
DataPublication.schema = {
  type: 'data-publication',
  title: STRING,
  authors: CHILDREN('ref-contrib'),
  containerTitle: STRING, // <source>
  year: STRING,
  month: STRING,
  day: STRING,
  accessionId: STRING,
  arkId: STRING,
  archiveId: STRING,
  doi: STRING
}

class JournalArticle extends BibliographicEntry {}
JournalArticle.schema = {
  type: 'journal-article',
  title: STRING,
  authors: CHILDREN('ref-contrib'),
  editors: CHILDREN('ref-contrib'),
  containerTitle: STRING, // <source>
  volume: STRING,
  issue: STRING,
  year: STRING,
  month: STRING,
  day: STRING,
  fpage: STRING,
  lpage: STRING,
  pageRange: STRING,
  elocationId: STRING,
  doi: STRING,
  pmid: STRING
}

class MagazineArticle extends BibliographicEntry {}
MagazineArticle.schema = {
  type: 'magazine-article',
  title: STRING,
  authors: CHILDREN('ref-contrib'),
  containerTitle: STRING, // <source>
  year: STRING,
  month: STRING,
  day: STRING,
  volume: STRING,
  fpage: STRING,
  lpage: STRING,
  pageRange: STRING,
  doi: STRING
}

class NewspaperArticle extends BibliographicEntry {}
NewspaperArticle.schema = {
  type: 'newspaper-article',
  title: STRING,
  authors: CHILDREN('ref-contrib'),
  containerTitle: STRING, // <source>
  year: STRING,
  month: STRING,
  day: STRING,
  volume: STRING,
  fpage: STRING,
  lpage: STRING,
  pageRange: STRING,
  doi: STRING,
  edition: STRING,
  partTitle: STRING
}

class Patent extends BibliographicEntry {}
Patent.schema = {
  // HACK: trying to merge EntitDb into Article model, avoiding type collision
  type: '_patent',
  inventors: CHILDREN('ref-contrib'),
  assignee: STRING,
  title: STRING,
  containerTitle: STRING, // <source>
  year: STRING,
  month: STRING,
  day: STRING,
  patentNumber: STRING,
  patentCountry: STRING,
  doi: STRING
}

class Report extends BibliographicEntry {
  getGuid () {
    return this.isbn
  }
}
Report.schema = {
  type: 'report',
  authors: CHILDREN('ref-contrib'),
  sponsors: CHILDREN('ref-contrib'),
  title: STRING,
  year: STRING,
  month: STRING,
  day: STRING,
  publisherName: STRING,
  publisherLoc: STRING,
  series: STRING,
  isbn: STRING,
  doi: STRING
}

class Software extends BibliographicEntry {}
Software.schema = {
  type: 'software',
  title: STRING,
  authors: CHILDREN('ref-contrib'),
  version: STRING,
  publisherLoc: STRING,
  publisherName: STRING,
  year: STRING,
  month: STRING,
  day: STRING,
  doi: STRING
}

class Thesis extends BibliographicEntry {}
Thesis.schema = {
  type: 'thesis',
  title: STRING,
  authors: CHILDREN('ref-contrib'),
  year: STRING,
  month: STRING,
  day: STRING,
  publisherLoc: STRING,
  publisherName: STRING,
  doi: STRING
}

class Webpage extends BibliographicEntry {}
Webpage.schema = {
  type: 'webpage',
  title: STRING,
  // E.g. website name, where the page appeared
  containerTitle: STRING, // <source>
  authors: CHILDREN('ref-contrib'),
  year: STRING,
  month: STRING,
  day: STRING,
  publisherLoc: STRING,
  uri: STRING
}

class Person extends DocumentNode {}
Person.schema = {
  type: 'person',
  givenNames: STRING,
  surname: STRING,
  prefix: STRING,
  suffix: STRING,
  email: STRING,
  orcid: STRING,
  group: ONE('group'),
  affiliations: MANY('organisation'),
  awards: MANY('award'),
  equalContrib: BOOLEAN,
  corresp: BOOLEAN,
  deceased: BOOLEAN
}

/* Holds data for persons and instituions/groups in references */
export class RefContrib extends DocumentNode {}
RefContrib.schema = {
  type: 'ref-contrib',
  name: STRING, // either family name or institution name
  givenNames: STRING
}

class Award extends DocumentNode {}
Award.schema = {
  type: 'award',
  institution: STRING,
  fundRefId: STRING,
  awardId: STRING
}

export class Group extends DocumentNode {}
Group.schema = {
  type: 'group',
  name: STRING,
  email: STRING,
  affiliations: MANY('organisation'),
  awards: MANY('award'),
  equalContrib: BOOLEAN,
  corresp: BOOLEAN
}

class Keyword extends DocumentNode {}
Keyword.schema = {
  type: 'keyword',
  name: STRING,
  category: STRING,
  language: STRING
}

export class Organisation extends DocumentNode {}
Organisation.schema = {
  type: 'organisation',
  name: STRING,
  division1: STRING,
  division2: STRING,
  division3: STRING,
  // Consider switching to address-line1,2,3
  street: STRING,
  addressComplements: STRING,
  city: STRING,
  state: STRING,
  postalCode: STRING,
  country: STRING,
  phone: STRING,
  fax: STRING,
  email: STRING,
  uri: STRING
}

class Subject extends DocumentNode {}
Subject.schema = {
  // HACK: trying to merge EntitDb into Article model, avoiding type collision
  type: '_subject',
  name: STRING,
  category: STRING,
  language: STRING
}

class ContainerTranslation extends XMLContainerNode {}
ContainerTranslation.type = 'container-translation'
ContainerTranslation.language = STRING

class TextTranslation extends XMLTextElement {}
TextTranslation.schema = {
  type: 'text-translation',
  content: STRING,
  language: STRING
}

class UnsupportedNode extends DocumentNode {}
UnsupportedNode.schema = {
  type: 'unsupported-node',
  data: 'string'
}

class UnsupportedInlineNode extends InlineNode {}
UnsupportedInlineNode.schema = {
  type: 'unsupported-inline-node',
  data: 'string'
}

const InternalArticleSchema = new DocumentSchema({
  name: 'TextureInternalArticle',
  version: '0.1.0',
  DocumentClass: InternalArticleDocument
})

InternalArticleSchema.addNodes([
  Article,
  // metadata
  Metadata,
  ArticleRecord,
  Organisations,
  Authors,
  Awards,
  Groups,
  Editors,
  Keywords,
  Subjects,
  // entities used in metadata
  Award,
  Group,
  Person,
  Organisation,
  Keyword,
  Subject,
  // content
  Content,
  Front,
  Title,
  Abstract,
  Heading,
  Back,
  References,
  Footnotes,
  // bibliography
  BibliographicEntry,
  Book,
  Chapter,
  ConferencePaper,
  DataPublication,
  JournalArticle,
  MagazineArticle,
  NewspaperArticle,
  Report,
  Patent,
  Software,
  Thesis,
  Webpage,
  // entity used in bibliography
  RefContrib,
  // others
  UnsupportedNode,
  UnsupportedInlineNode
])

// Elements taken from the JATS spec
// TODO: make sure that we do not need to modify them, e.g. marking them as inline nodes
InternalArticleSchema.addNodes([
  'body',
  'fn',
  'p',
  'label',
  'tex-math',
  // formatting
  'bold',
  'fixed-case',
  'italic',
  'monospace',
  'overline',
  'roman',
  'sans-serif',
  'sc',
  'strike',
  'sub',
  'sup',
  'underline',
  'ruby',
  // annos and inline-nodes
  'abbrev',
  'break',
  'chem-struct',
  'ext-link',
  'hr',
  'named-content',
  'inline-formula',
  'inline-graphic',
  'styled-content',
  'x',
  'xref'
].map(name => TextureArticleSchema.getNodeClass(name)))

export default InternalArticleSchema
<commit_msg>Translatable elements schema fix.<commit_after>import {
  DocumentSchema, DocumentNode, InlineNode,
  XMLContainerNode, XMLElementNode, XMLTextElement
} from 'substance'
import { BOOLEAN, STRING, MANY, ONE, CHILDREN } from '../kit'
import { INTERNAL_BIBR_TYPES } from './ArticleConstants'
import InternalArticleDocument from './InternalArticleDocument'
// TODO: rename this to *Schema
import TextureArticleSchema from './TextureArticle'

/*
  TODO: we want to move away from a JATS oriented internal model.

  The internal model structures the data in different categories: content vs metadata.
  It is a challenge to define the boundary between these two categories.
  Here are some criteria:
  - Is the content displayed in a classical manuscript?
  - May the content contain citations, or references to other displayed elements?
*/

class Article extends XMLElementNode {}
Article.schema = {
  type: 'article',
  _childNodes: CHILDREN('metadata', 'content')
}

class ArticleRecord extends DocumentNode {}
ArticleRecord.schema = {
  type: 'article-record',
  volume: STRING,
  issue: STRING,
  fpage: STRING,
  lpage: STRING,
  pageRange: STRING,
  elocationId: STRING,
  acceptedDate: STRING,
  publishedDate: STRING,
  receivedDate: STRING,
  revReceivedDate: STRING,
  revRequestedDate: STRING
}

class TranslatableTextElement extends XMLTextElement {}
TranslatableTextElement.schema = {
  translations: CHILDREN('text-translation')
}

class TranslatableContainerElement extends XMLContainerNode {}
TranslatableContainerElement.schema = {
  translations: CHILDREN('container-translation')
}

class Metadata extends XMLElementNode {}
Metadata.schema = {
  type: 'metadata',
  _childNodes: CHILDREN(
    'article-record', 'authors', 'editors', 'groups', 'organisations', 'awards', 'keywords', 'subjects'
  )
}

class Organisations extends XMLElementNode {}
Organisations.schema = {
  type: 'organisations',
  _childNodes: CHILDREN(...INTERNAL_BIBR_TYPES)
}

class Authors extends XMLElementNode {}
Authors.schema = {
  type: 'authors',
  _childNodes: CHILDREN('person')
}

class Editors extends XMLElementNode {}
Editors.schema = {
  type: 'editors',
  _childNodes: CHILDREN('person')
}

class Groups extends XMLElementNode {}
Groups.schema = {
  type: 'groups',
  _childNodes: CHILDREN('group')
}

class Awards extends XMLElementNode {}
Awards.schema = {
  type: 'awards',
  _childNodes: CHILDREN('award')
}

class Keywords extends XMLElementNode {}
Keywords.schema = {
  type: 'keywords',
  _childNodes: CHILDREN('award')
}

class Subjects extends XMLElementNode {}
Subjects.schema = {
  type: 'subjects',
  _childNodes: CHILDREN('award')
}

// TODO: as this node has a fixed layout, we might want to use a classical DocumentNode
// But this needs support for CSS select
class Content extends XMLElementNode {}
Content.schema = {
  type: 'content',
  _childNodes: CHILDREN('front', 'body', 'back')
}

class Front extends XMLElementNode {}
Front.schema = {
  type: 'front',
  _childNodes: CHILDREN('title', 'abstract')
}

class Back extends XMLElementNode {}
Back.schema = {
  type: 'back',
  _childNodes: CHILDREN('references', 'footnotes')
}

class Title extends TranslatableTextElement {}
Title.type = 'title'

class Abstract extends TranslatableContainerElement {}
Abstract.type = 'abstract'

class Heading extends XMLTextElement {}
Heading.type = 'heading'

class References extends XMLElementNode {}
References.schema = {
  type: 'references',
  _childNodes: CHILDREN(...INTERNAL_BIBR_TYPES)
}

class Footnotes extends XMLElementNode {}
Footnotes.schema = {
  type: 'footnotes',
  _childNodes: CHILDREN('fn')
}

// TODO: move all of this into InternalArticleSchema

class BibliographicEntry extends DocumentNode {}
BibliographicEntry.schema = {
  type: 'bibr'
}

class Book extends BibliographicEntry {}
Book.schema = {
  type: 'book',
  authors: CHILDREN('ref-contrib'),
  editors: CHILDREN('ref-contrib'),
  translators: CHILDREN('ref-contrib'),
  title: STRING,
  volume: STRING,
  edition: STRING,
  publisherLoc: STRING,
  publisherName: STRING,
  year: STRING,
  month: STRING,
  day: STRING,
  pageCount: STRING,
  series: STRING,
  doi: STRING,
  isbn: STRING,
  pmid: STRING
}

class Chapter extends BibliographicEntry {}
Chapter.schema = {
  type: 'chapter',
  title: STRING, // <chapter-title>
  containerTitle: STRING, // <source>
  volume: STRING,
  authors: CHILDREN('ref-contrib'), // <person-group person-group-type="author">
  editors: CHILDREN('ref-contrib'),
  translators: CHILDREN('ref-contrib'),
  edition: STRING,
  publisherLoc: STRING,
  publisherName: STRING,
  year: STRING,
  month: STRING,
  day: STRING,
  fpage: STRING,
  lpage: STRING,
  pageRange: STRING,
  elocationId: STRING,
  series: STRING,
  doi: STRING, // <pub-id pub-id-type="doi">
  isbn: STRING, // <pub-id pub-id-type="isbn">
  pmid: STRING // <pub-id pub-id-type="pmid">
}

class ConferencePaper extends BibliographicEntry {}
ConferencePaper.schema = {
  type: 'conference-paper',
  title: STRING, // <article-title>
  authors: CHILDREN('ref-contrib'),
  confName: STRING,
  confLoc: STRING,
  containerTitle: STRING, // <source>
  year: STRING,
  month: STRING,
  day: STRING,
  fpage: STRING,
  lpage: STRING,
  pageRange: STRING,
  elocationId: STRING,
  doi: STRING
}

class DataPublication extends BibliographicEntry {}
DataPublication.schema = {
  type: 'data-publication',
  title: STRING,
  authors: CHILDREN('ref-contrib'),
  containerTitle: STRING, // <source>
  year: STRING,
  month: STRING,
  day: STRING,
  accessionId: STRING,
  arkId: STRING,
  archiveId: STRING,
  doi: STRING
}

class JournalArticle extends BibliographicEntry {}
JournalArticle.schema = {
  type: 'journal-article',
  title: STRING,
  authors: CHILDREN('ref-contrib'),
  editors: CHILDREN('ref-contrib'),
  containerTitle: STRING, // <source>
  volume: STRING,
  issue: STRING,
  year: STRING,
  month: STRING,
  day: STRING,
  fpage: STRING,
  lpage: STRING,
  pageRange: STRING,
  elocationId: STRING,
  doi: STRING,
  pmid: STRING
}

class MagazineArticle extends BibliographicEntry {}
MagazineArticle.schema = {
  type: 'magazine-article',
  title: STRING,
  authors: CHILDREN('ref-contrib'),
  containerTitle: STRING, // <source>
  year: STRING,
  month: STRING,
  day: STRING,
  volume: STRING,
  fpage: STRING,
  lpage: STRING,
  pageRange: STRING,
  doi: STRING
}

class NewspaperArticle extends BibliographicEntry {}
NewspaperArticle.schema = {
  type: 'newspaper-article',
  title: STRING,
  authors: CHILDREN('ref-contrib'),
  containerTitle: STRING, // <source>
  year: STRING,
  month: STRING,
  day: STRING,
  volume: STRING,
  fpage: STRING,
  lpage: STRING,
  pageRange: STRING,
  doi: STRING,
  edition: STRING,
  partTitle: STRING
}

class Patent extends BibliographicEntry {}
Patent.schema = {
  // HACK: trying to merge EntitDb into Article model, avoiding type collision
  type: '_patent',
  inventors: CHILDREN('ref-contrib'),
  assignee: STRING,
  title: STRING,
  containerTitle: STRING, // <source>
  year: STRING,
  month: STRING,
  day: STRING,
  patentNumber: STRING,
  patentCountry: STRING,
  doi: STRING
}

class Report extends BibliographicEntry {
  getGuid () {
    return this.isbn
  }
}
Report.schema = {
  type: 'report',
  authors: CHILDREN('ref-contrib'),
  sponsors: CHILDREN('ref-contrib'),
  title: STRING,
  year: STRING,
  month: STRING,
  day: STRING,
  publisherName: STRING,
  publisherLoc: STRING,
  series: STRING,
  isbn: STRING,
  doi: STRING
}

class Software extends BibliographicEntry {}
Software.schema = {
  type: 'software',
  title: STRING,
  authors: CHILDREN('ref-contrib'),
  version: STRING,
  publisherLoc: STRING,
  publisherName: STRING,
  year: STRING,
  month: STRING,
  day: STRING,
  doi: STRING
}

class Thesis extends BibliographicEntry {}
Thesis.schema = {
  type: 'thesis',
  title: STRING,
  authors: CHILDREN('ref-contrib'),
  year: STRING,
  month: STRING,
  day: STRING,
  publisherLoc: STRING,
  publisherName: STRING,
  doi: STRING
}

class Webpage extends BibliographicEntry {}
Webpage.schema = {
  type: 'webpage',
  title: STRING,
  // E.g. website name, where the page appeared
  containerTitle: STRING, // <source>
  authors: CHILDREN('ref-contrib'),
  year: STRING,
  month: STRING,
  day: STRING,
  publisherLoc: STRING,
  uri: STRING
}

class Person extends DocumentNode {}
Person.schema = {
  type: 'person',
  givenNames: STRING,
  surname: STRING,
  prefix: STRING,
  suffix: STRING,
  email: STRING,
  orcid: STRING,
  group: ONE('group'),
  affiliations: MANY('organisation'),
  awards: MANY('award'),
  equalContrib: BOOLEAN,
  corresp: BOOLEAN,
  deceased: BOOLEAN
}

/* Holds data for persons and instituions/groups in references */
export class RefContrib extends DocumentNode {}
RefContrib.schema = {
  type: 'ref-contrib',
  name: STRING, // either family name or institution name
  givenNames: STRING
}

class Award extends DocumentNode {}
Award.schema = {
  type: 'award',
  institution: STRING,
  fundRefId: STRING,
  awardId: STRING
}

export class Group extends DocumentNode {}
Group.schema = {
  type: 'group',
  name: STRING,
  email: STRING,
  affiliations: MANY('organisation'),
  awards: MANY('award'),
  equalContrib: BOOLEAN,
  corresp: BOOLEAN
}

class Keyword extends DocumentNode {}
Keyword.schema = {
  type: 'keyword',
  name: STRING,
  category: STRING,
  language: STRING
}

export class Organisation extends DocumentNode {}
Organisation.schema = {
  type: 'organisation',
  name: STRING,
  division1: STRING,
  division2: STRING,
  division3: STRING,
  // Consider switching to address-line1,2,3
  street: STRING,
  addressComplements: STRING,
  city: STRING,
  state: STRING,
  postalCode: STRING,
  country: STRING,
  phone: STRING,
  fax: STRING,
  email: STRING,
  uri: STRING
}

class Subject extends DocumentNode {}
Subject.schema = {
  // HACK: trying to merge EntitDb into Article model, avoiding type collision
  type: '_subject',
  name: STRING,
  category: STRING,
  language: STRING
}

class ContainerTranslation extends XMLContainerNode {}
ContainerTranslation.type = 'container-translation'
ContainerTranslation.language = STRING

class TextTranslation extends XMLTextElement {}
TextTranslation.schema = {
  type: 'text-translation',
  content: STRING,
  language: STRING
}

class UnsupportedNode extends DocumentNode {}
UnsupportedNode.schema = {
  type: 'unsupported-node',
  data: 'string'
}

class UnsupportedInlineNode extends InlineNode {}
UnsupportedInlineNode.schema = {
  type: 'unsupported-inline-node',
  data: 'string'
}

const InternalArticleSchema = new DocumentSchema({
  name: 'TextureInternalArticle',
  version: '0.1.0',
  DocumentClass: InternalArticleDocument
})

InternalArticleSchema.addNodes([
  Article,
  // metadata
  Metadata,
  ArticleRecord,
  Organisations,
  Authors,
  Awards,
  Groups,
  Editors,
  Keywords,
  Subjects,
  // entities used in metadata
  Award,
  Group,
  Person,
  Organisation,
  Keyword,
  Subject,
  // content
  Content,
  Front,
  Title,
  Abstract,
  Heading,
  Back,
  References,
  Footnotes,
  // bibliography
  BibliographicEntry,
  Book,
  Chapter,
  ConferencePaper,
  DataPublication,
  JournalArticle,
  MagazineArticle,
  NewspaperArticle,
  Report,
  Patent,
  Software,
  Thesis,
  Webpage,
  // entity used in bibliography
  RefContrib,
  // others
  UnsupportedNode,
  UnsupportedInlineNode
])

// Elements taken from the JATS spec
// TODO: make sure that we do not need to modify them, e.g. marking them as inline nodes
InternalArticleSchema.addNodes([
  'body',
  'fn',
  'p',
  'label',
  'tex-math',
  // formatting
  'bold',
  'fixed-case',
  'italic',
  'monospace',
  'overline',
  'roman',
  'sans-serif',
  'sc',
  'strike',
  'sub',
  'sup',
  'underline',
  'ruby',
  // annos and inline-nodes
  'abbrev',
  'break',
  'chem-struct',
  'ext-link',
  'hr',
  'named-content',
  'inline-formula',
  'inline-graphic',
  'styled-content',
  'x',
  'xref'
].map(name => TextureArticleSchema.getNodeClass(name)))

export default InternalArticleSchema
<|endoftext|>


<commit_before>(function() {
    var getValidMethod = function(method) {
        if (method) {
            var proposedMethod = method.toUpperCase();

            if (['GET', 'POST', 'PUT'].indexOf(proposedMethod) >= 0) {
                return proposedMethod;
            }
        }
    },

    // NOTE: Safari doesn't have any visual indications when submit is blocked
    interceptSubmit = function() {
        // Intercept submit event
        this.addEventListener('submit', function(event) {
            // Stop form submission.  Believe it or not,
            // both of these are required for some reason,
            // and returning false doesn't seem to reliably work.
            event.preventDefault();
            event.stopPropagation();

            // respect any field validation attributes
            if (this.checkValidity()) {
                this.fire('submitting');
                if ('multipart/form-data' !== this.enctype) {
                    sendUrlencodedForm.call(this, this);
                }
                else {
                    if ('GET' === this.acceptableMethod) {
                        sendUrlencodedForm.call(this, this);
                    }
                    else {
                        sendMultipartForm.call(this, this);
                    }
                }
            }
        }.bind(this));

        // Intercept native form submit function.
        // In order to force the browser to highlight the invalid fields,
        // we need to create a hidden submit button and click it if the form is invalid.
        var fakeSubmitEl = document.createElement('input');
        fakeSubmitEl.setAttribute('type', 'submit');
        fakeSubmitEl.style.display = 'none';
        this.appendChild(fakeSubmitEl);
        this.submit = function() {
            if (this.checkValidity()) {
                this.fire('submit');
            }
            else {
                fakeSubmitEl.click();
            }
        };
    },

    listenForAjaxComplete = function() {
        var sender = this.shadowRoot.getElementsByTagName('core-ajax')[0];

        sender.addEventListener('core-complete', function(event) {
             this.fire('submitted', event.detail.xhr);
        }.bind(this));
    },

    // @TODO: should these FormData parse methods be exposed as events
    // if, say, someone wanted to filter or transform the data in a form
    // (i.e., radio from yes/no to true/false, or textarea from markdown to
    // html)?
    parseFormData = function(form) {
        var formData = new FormData(window.unwrap(form)),
            fileInput = form.getElementsByTagName('file-input')[0];

        if (fileInput) {
            var fileInputName = fileInput.getAttribute('name') || 'files';

            if (fileInput.files.length > 1) {
                fileInputName += '[]';
            }

            fileInput.files.forEach(function(file) {
                formData.append(fileInputName, file);
            });
        }

        return formData;

    },

    /**
     * Parse an `HTMLRadioElement`'s value, returning the value iff
     * the element has a present `checked` attribute.
     *
     * @param HTMLRadioElement element
     * @return mixed The element's value
     */
    parseRadioElementValue = function(element) {
        var value;
        if (element.checked === true) {
            value = element.value;
        }
        return value;

    },

    /**
     * Parse an `HTMLOptionElement`'s value, returning the value iff
     * the element has a present `selected` attribute.
     * @param HTMLOptionElement element
     * @return mixed The element's value
     */
    parseSelectOptionElementValue = function(element) {
        var elementValue;
        if (element.selected === true){
            elementValue = element.value;
        }
        return elementValue;
    },

    /**
     * Parse an `HTMLOptGroupElement` return the `HTMLOptionElement` that
     * has a `checked` attribute.
     * @param HTMLOptGroupElement element
     * @return mixed The element's value
     */
    parseSelectOptgroupElementValue = function(element) {
        var elementValue;
        Array.prototype.forEach.call(element.options, function(optionElement){
            var tempElementValue = parseSelectOptionElementValue(optionElement);
            if (tempElementValue){
                elementValue = tempElementValue;
            }
        });
        return elementValue;
    },

    /**
     * Parse an `HTMLSelectElement`'s value.
     *
     * @param HTMLSelectElement element
     * @return mixed The element's selected values
     */
    parseSelectElementValues = function(element) {
        var elementValues = [];

        Array.prototype.forEach.call(element.options, function(optionElement){
            var tempElementValue = parseSelectOptionElementValue(optionElement);
            tempElementValue && elementValues.push(tempElementValue);
        });

        return elementValues;
    },

    /**
     * Parse an `HTMLInputElement`'s value.
     * @param HTMLInputElement element
     * @return mixed The element's value
     */
    parseInputElementValue = function(element){
        var elementValue,
            elementType = element.type;

        if (element.disabled === true ||
            ['submit', 'reset', 'button', 'image'].indexOf(elementType) !== -1) {
             // do nothing for these button types
        }
        else if (elementType === 'radio') {
            elementValue = parseRadioElementValue(element);
        } else {
            elementValue = element.value;
        }

        return elementValue;
    },

    /**
     * Return the value of some `HTMLElement`s  value attribute if possible.
     * @param HTMLElement element
     * @return mixed The element's value attribute
     */
    parseElementValue = function(element){
        var elementValue,
            elementTag = element.tagName.toLowerCase();

        if (elementTag === 'input') {
            elementValue = parseInputElementValue(element);
        }
        else if (elementTag === 'textarea'){
            elementValue = element.value;
        }
        //else if(/select*/.exec(elementTag)) {
        else if (elementTag === 'select') {
             elementValue = parseSelectElementValues(element);
        }

        return elementValue;

    },

    /**
     * Parse an `HTMLFormElement` into key value pairs
     * @param HTMLFormElement form
     * @return Object key, value pairs representing the html form
     */
    parseForm = function(form) {
        var formObj = {},
            formElements = form.getElementsByTagName('input');

        formElements = Array.prototype.slice.call(formElements);
        formElements = formElements.concat(Array.prototype.slice.call(form.getElementsByTagName('select')));
        formElements = formElements.concat(Array.prototype.slice.call(form.getElementsByTagName('textarea')));

        formElements.forEach(function(formElement){
            var key = formElement.name,
                val = parseElementValue(formElement);

            if (key && val) {
                formObj[key] = val;
            }
        });

        return formObj;
    },

    /**
     * Send a url-encoded `HTMLFormElement` in the URL query string.
     * @param HTMLFormElement form
     */
    sendUrlencodedForm = function(form){
        var sender = this.shadowRoot.getElementsByTagName('core-ajax')[0],
            // We must URL encode the data and place it in the body or
            // query paramter section of the URI (depending on the method).
            // core-ajax attempts to do this for us, but this requires we pass
            // an Object to core-ajax with the params and we cannot properly
            // express multiple values for a <select> (which is possible)
            // via a JavaScript Object.
            data = toQueryString(parseForm(form));

        if (this.cookies) {
            sender.withCredentials = true;
        }

        if (this.acceptableMethod === 'POST') {
            sender.body = data;
        }
        else {
            sender.url += (sender.url.indexOf('?') > 0 ? '&' : '?') + data;
        }

        sender.go();
    },

    /**
     * Send a multipart-encoded `HTMLFormElement` in the request body.
     * @param HTMLFormElement form
     */
    sendMultipartForm = function(form) {
        var sender = this.shadowRoot.getElementsByTagName('core-ajax')[0],
            data = parseFormData(form);

        // make sure Polymer/core-ajax doesn't touch the Content-Type.
        // The browser must set this with the proper multipart boundary ID.
        sender.contentType = null;

        if (this.cookies) {
            sender.withCredentials = true;
        }

        sender.body = data;
        sender.go();
    },

    toQueryString = function(params) {
        var queryParams = [];

        Object.keys(params).forEach(function(key) {
            var val = params[key];
            key = encodeURIComponent(key);

            if (val && Object.prototype.toString.call(val) === '[object Array]') {
                val.forEach(function(valInArray) {
                    queryParams.push(key + '=' + encodeURIComponent(valInArray));
                });
            }
            else {
                queryParams.push(val == null ? key : (key + '=' + encodeURIComponent(val)));
            }
        });

        return queryParams.join('&');
      },

    watchForInvalidFields = function(form) {
        var customEl = this,
            fields = form.getElementsByTagName('input'),
            invalidFields = [],
            timer = null;

        fields = Array.prototype.slice.call(fields);
        fields = fields.concat(Array.prototype.slice.call(form.getElementsByTagName('select')));
        fields = fields.concat(Array.prototype.slice.call(form.getElementsByTagName('textarea')));

        fields.forEach(function(field) {
            field.addEventListener('invalid', function() {
                invalidFields.push(this);

                // In case another element is invalid and the event
                // hasn't been triggered yet, hold off on firing the
                // invalid event on the custom el.
                clearTimeout(timer);
                timer = setTimeout(function() {
                    customEl.fire('invalid', invalidFields);
                    invalidFields = [];
                    console.error('Form submission blocked - constraints violation.');
                }, 10);
            });
        });
    };

    this.ajaxForm = {
       /**
        * Fired when a response is received.
        *
        * @event core-response
        */
        cookies: false,

        domReady: function() {
            // The method attribute set on the light-DOM `<form>`
            // can't seem to be accessed as a property of this element,
            // unlike other attributes.  Perhaps due to the fact that
            // we are extending a form and a "natural" form also has a
            // method attr?  Perhaps something special about this attr?
            // Need to look into this further.
            this.acceptableMethod = getValidMethod(this.getAttribute('method'));

            if (!this.acceptableMethod) {
                throw new Error('Invalid method!');
            }

            watchForInvalidFields.call(this, this);

            interceptSubmit.call(this);

            listenForAjaxComplete.call(this);
        }
    };
}());
<commit_msg>refactor($indent): fix indent<commit_after>(function() {
    var getValidMethod = function(method) {
            if (method) {
                var proposedMethod = method.toUpperCase();

                if (['GET', 'POST', 'PUT'].indexOf(proposedMethod) >= 0) {
                    return proposedMethod;
                }
            }
        },

        // NOTE: Safari doesn't have any visual indications when submit is blocked
        interceptSubmit = function() {
            // Intercept submit event
            this.addEventListener('submit', function(event) {
                // Stop form submission.  Believe it or not,
                // both of these are required for some reason,
                // and returning false doesn't seem to reliably work.
                event.preventDefault();
                event.stopPropagation();

                // respect any field validation attributes
                if (this.checkValidity()) {
                    this.fire('submitting');
                    if ('multipart/form-data' !== this.enctype) {
                        sendUrlencodedForm.call(this, this);
                    }
                    else {
                        if ('GET' === this.acceptableMethod) {
                            sendUrlencodedForm.call(this, this);
                        }
                        else {
                            sendMultipartForm.call(this, this);
                        }
                    }
                }
            }.bind(this));

            // Intercept native form submit function.
            // In order to force the browser to highlight the invalid fields,
            // we need to create a hidden submit button and click it if the form is invalid.
            var fakeSubmitEl = document.createElement('input');
            fakeSubmitEl.setAttribute('type', 'submit');
            fakeSubmitEl.style.display = 'none';
            this.appendChild(fakeSubmitEl);
            this.submit = function() {
                if (this.checkValidity()) {
                    this.fire('submit');
                }
                else {
                    fakeSubmitEl.click();
                }
            };
        },

        listenForAjaxComplete = function() {
            var sender = this.shadowRoot.getElementsByTagName('core-ajax')[0];

            sender.addEventListener('core-complete', function(event) {
                 this.fire('submitted', event.detail.xhr);
            }.bind(this));
        },

        // @TODO: should these FormData parse methods be exposed as events
        // if, say, someone wanted to filter or transform the data in a form
        // (i.e., radio from yes/no to true/false, or textarea from markdown to
        // html)?
        parseFormData = function(form) {
            var formData = new FormData(window.unwrap(form)),
                fileInput = form.getElementsByTagName('file-input')[0];

            if (fileInput) {
                var fileInputName = fileInput.getAttribute('name') || 'files';

                if (fileInput.files.length > 1) {
                    fileInputName += '[]';
                }

                fileInput.files.forEach(function(file) {
                    formData.append(fileInputName, file);
                });
            }

            return formData;

        },

        /**
         * Parse an `HTMLRadioElement`'s value, returning the value iff
         * the element has a present `checked` attribute.
         *
         * @param HTMLRadioElement element
         * @return mixed The element's value
         */
        parseRadioElementValue = function(element) {
            var value;
            if (element.checked === true) {
                value = element.value;
            }
            return value;

        },

        /**
         * Parse an `HTMLOptionElement`'s value, returning the value iff
         * the element has a present `selected` attribute.
         * @param HTMLOptionElement element
         * @return mixed The element's value
         */
        parseSelectOptionElementValue = function(element) {
            var elementValue;
            if (element.selected === true){
                elementValue = element.value;
            }
            return elementValue;
        },

        /**
         * Parse an `HTMLOptGroupElement` return the `HTMLOptionElement` that
         * has a `checked` attribute.
         * @param HTMLOptGroupElement element
         * @return mixed The element's value
         */
        parseSelectOptgroupElementValue = function(element) {
            var elementValue;
            Array.prototype.forEach.call(element.options, function(optionElement){
                var tempElementValue = parseSelectOptionElementValue(optionElement);
                if (tempElementValue){
                    elementValue = tempElementValue;
                }
            });
            return elementValue;
        },

        /**
         * Parse an `HTMLSelectElement`'s value.
         *
         * @param HTMLSelectElement element
         * @return mixed The element's selected values
         */
        parseSelectElementValues = function(element) {
            var elementValues = [];

            Array.prototype.forEach.call(element.options, function(optionElement){
                var tempElementValue = parseSelectOptionElementValue(optionElement);
                tempElementValue && elementValues.push(tempElementValue);
            });

            return elementValues;
        },

        /**
         * Parse an `HTMLInputElement`'s value.
         * @param HTMLInputElement element
         * @return mixed The element's value
         */
        parseInputElementValue = function(element){
            var elementValue,
                elementType = element.type;

            if (element.disabled === true ||
                ['submit', 'reset', 'button', 'image'].indexOf(elementType) !== -1) {
                 // do nothing for these button types
            }
            else if (elementType === 'radio') {
                elementValue = parseRadioElementValue(element);
            } else {
                elementValue = element.value;
            }

            return elementValue;
        },

        /**
         * Return the value of some `HTMLElement`s  value attribute if possible.
         * @param HTMLElement element
         * @return mixed The element's value attribute
         */
        parseElementValue = function(element){
            var elementValue,
                elementTag = element.tagName.toLowerCase();

            if (elementTag === 'input') {
                elementValue = parseInputElementValue(element);
            }
            else if (elementTag === 'textarea'){
                elementValue = element.value;
            }
            //else if(/select*/.exec(elementTag)) {
            else if (elementTag === 'select') {
                 elementValue = parseSelectElementValues(element);
            }

            return elementValue;

        },

        /**
         * Parse an `HTMLFormElement` into key value pairs
         * @param HTMLFormElement form
         * @return Object key, value pairs representing the html form
         */
        parseForm = function(form) {
            var formObj = {},
                formElements = form.getElementsByTagName('input');

            formElements = Array.prototype.slice.call(formElements);
            formElements = formElements.concat(Array.prototype.slice.call(form.getElementsByTagName('select')));
            formElements = formElements.concat(Array.prototype.slice.call(form.getElementsByTagName('textarea')));

            formElements.forEach(function(formElement){
                var key = formElement.name,
                    val = parseElementValue(formElement);

                if (key && val) {
                    formObj[key] = val;
                }
            });

            return formObj;
        },

        /**
         * Send a url-encoded `HTMLFormElement` in the URL query string.
         * @param HTMLFormElement form
         */
        sendUrlencodedForm = function(form){
            var sender = this.shadowRoot.getElementsByTagName('core-ajax')[0],
                // We must URL encode the data and place it in the body or
                // query paramter section of the URI (depending on the method).
                // core-ajax attempts to do this for us, but this requires we pass
                // an Object to core-ajax with the params and we cannot properly
                // express multiple values for a <select> (which is possible)
                // via a JavaScript Object.
                data = toQueryString(parseForm(form));

            if (this.cookies) {
                sender.withCredentials = true;
            }

            if (this.acceptableMethod === 'POST') {
                sender.body = data;
            }
            else {
                sender.url += (sender.url.indexOf('?') > 0 ? '&' : '?') + data;
            }

            sender.go();
        },

        /**
         * Send a multipart-encoded `HTMLFormElement` in the request body.
         * @param HTMLFormElement form
         */
        sendMultipartForm = function(form) {
            var sender = this.shadowRoot.getElementsByTagName('core-ajax')[0],
                data = parseFormData(form);

            // make sure Polymer/core-ajax doesn't touch the Content-Type.
            // The browser must set this with the proper multipart boundary ID.
            sender.contentType = null;

            if (this.cookies) {
                sender.withCredentials = true;
            }

            sender.body = data;
            sender.go();
        },

        toQueryString = function(params) {
            var queryParams = [];

            Object.keys(params).forEach(function(key) {
                var val = params[key];
                key = encodeURIComponent(key);

                if (val && Object.prototype.toString.call(val) === '[object Array]') {
                    val.forEach(function(valInArray) {
                        queryParams.push(key + '=' + encodeURIComponent(valInArray));
                    });
                }
                else {
                    queryParams.push(val == null ? key : (key + '=' + encodeURIComponent(val)));
                }
            });

            return queryParams.join('&');
          },

        watchForInvalidFields = function(form) {
            var customEl = this,
                fields = form.getElementsByTagName('input'),
                invalidFields = [],
                timer = null;

            fields = Array.prototype.slice.call(fields);
            fields = fields.concat(Array.prototype.slice.call(form.getElementsByTagName('select')));
            fields = fields.concat(Array.prototype.slice.call(form.getElementsByTagName('textarea')));

            fields.forEach(function(field) {
                field.addEventListener('invalid', function() {
                    invalidFields.push(this);

                    // In case another element is invalid and the event
                    // hasn't been triggered yet, hold off on firing the
                    // invalid event on the custom el.
                    clearTimeout(timer);
                    timer = setTimeout(function() {
                        customEl.fire('invalid', invalidFields);
                        invalidFields = [];
                        console.error('Form submission blocked - constraints violation.');
                    }, 10);
                });
            });
        };

    this.ajaxForm = {
       /**
        * Fired when a response is received.
        *
        * @event core-response
        */
        cookies: false,

        domReady: function() {
            // The method attribute set on the light-DOM `<form>`
            // can't seem to be accessed as a property of this element,
            // unlike other attributes.  Perhaps due to the fact that
            // we are extending a form and a "natural" form also has a
            // method attr?  Perhaps something special about this attr?
            // Need to look into this further.
            this.acceptableMethod = getValidMethod(this.getAttribute('method'));

            if (!this.acceptableMethod) {
                throw new Error('Invalid method!');
            }

            watchForInvalidFields.call(this, this);

            interceptSubmit.call(this);

            listenForAjaxComplete.call(this);
        }
    };
}());
<|endoftext|>


<commit_before>/**
 * @file gpf.attributes.AttributeAttribute attribute base class
 * @since 0.2.8
 */
/*#ifndef(UMD)*/
"use strict";
/*global _gpfAttribute*/ // Shortcut for gpf.attributes.Attribute
/*global _gpfAttributesCheckAppliedOnBaseClass*/ // Ensures attribute is applied on a specific base class
/*global _gpfAttributesCheckAppliedOnlyOnce*/ // Ensures attribute is used only once
/*global _gpfAttributesCheckClassOnly*/ // Ensures attribute is used only at class level
/*global _gpfCreateAbstractFunction*/ // Build a function that throws the abstractMethod exception
/*global _gpfDefine*/ // Shortcut for gpf.define
/*global _gpfIgnore*/ // Helper to remove unused parameter warning
/*exported _gpfAttributesAttributeAttribute*/ // Shortcut for gpf.attributes.AttributeAttribute
/*#endif*/

/**
 * Attribute for attributes
 *
 * @class gpf.attributes.AttributeAttribute
 * @private
 * @since 0.2.8
 */
var _gpfAttributesAttributeAttribute = _gpfDefine({
    $class: "gpf.attributes.AttributeAttribute",
    $extend: _gpfAttribute,
    $abstract: true,

    /**
     * @inheritdoc
     * @since 0.2.8
     */
    _check: function (member, classDefinition) {
        _gpfAttributesCheckClassOnly(member);
        _gpfAttributesCheckAppliedOnBaseClass(classDefinition, _gpfAttribute);
        _gpfAttributesCheckAppliedOnlyOnce(member, classDefinition, this.constructor);
    },

    /**
     * _check method 'injected' onto the target attribute
     *
     * @param {String} member Member name or empty if global to the class
     * @param {_GpfClassDefinition} classDefinition Class definition
     * @param {gpf.attributes.Attribute} targetAttribute Target attribute instance
     * @protected
     * @since 0.2.8
     */
    _targetCheck: _gpfCreateAbstractFunction(3),

    _overrideTargetCheck: function (classPrototype) {
        var me = this,
            initialCheck = classPrototype._check;
        classPrototype._check = function (member, classDefinition) {
            me._targetCheck(member, classDefinition, this);
            initialCheck.call(this, member, classDefinition);
        };
    },

    /**
     * @inheritdoc
     * @since 0.2.8
     */
    _build: function (member, classDefinition, classPrototype) {
        _gpfIgnore(member, classDefinition);
        this._overrideTargetCheck(classPrototype);
    }

});
<commit_msg>no-magic-numbers, no need to have the right number of parameters here (#280)<commit_after>/**
 * @file gpf.attributes.AttributeAttribute attribute base class
 * @since 0.2.8
 */
/*#ifndef(UMD)*/
"use strict";
/*global _gpfAttribute*/ // Shortcut for gpf.attributes.Attribute
/*global _gpfAttributesCheckAppliedOnBaseClass*/ // Ensures attribute is applied on a specific base class
/*global _gpfAttributesCheckAppliedOnlyOnce*/ // Ensures attribute is used only once
/*global _gpfAttributesCheckClassOnly*/ // Ensures attribute is used only at class level
/*global _gpfCreateAbstractFunction*/ // Build a function that throws the abstractMethod exception
/*global _gpfDefine*/ // Shortcut for gpf.define
/*global _gpfIgnore*/ // Helper to remove unused parameter warning
/*exported _gpfAttributesAttributeAttribute*/ // Shortcut for gpf.attributes.AttributeAttribute
/*#endif*/

/**
 * Attribute for attributes
 *
 * @class gpf.attributes.AttributeAttribute
 * @private
 * @since 0.2.8
 */
var _gpfAttributesAttributeAttribute = _gpfDefine({
    $class: "gpf.attributes.AttributeAttribute",
    $extend: _gpfAttribute,
    $abstract: true,

    /**
     * @inheritdoc
     * @since 0.2.8
     */
    _check: function (member, classDefinition) {
        _gpfAttributesCheckClassOnly(member);
        _gpfAttributesCheckAppliedOnBaseClass(classDefinition, _gpfAttribute);
        _gpfAttributesCheckAppliedOnlyOnce(member, classDefinition, this.constructor);
    },

    /**
     * _check method 'injected' onto the target attribute
     *
     * @param {String} member Member name or empty if global to the class
     * @param {_GpfClassDefinition} classDefinition Class definition
     * @param {gpf.attributes.Attribute} targetAttribute Target attribute instance
     * @protected
     * @since 0.2.8
     */
    _targetCheck: _gpfCreateAbstractFunction(),

    _overrideTargetCheck: function (classPrototype) {
        var me = this,
            initialCheck = classPrototype._check;
        classPrototype._check = function (member, classDefinition) {
            me._targetCheck(member, classDefinition, this);
            initialCheck.call(this, member, classDefinition);
        };
    },

    /**
     * @inheritdoc
     * @since 0.2.8
     */
    _build: function (member, classDefinition, classPrototype) {
        _gpfIgnore(member, classDefinition);
        this._overrideTargetCheck(classPrototype);
    }

});
<|endoftext|>


<commit_before>$(document).ready(function() {
  $(window).resize(function() {
    var height = $(window).height();
    $("#overview").height(height);
    $("#detail").height(height);
    $("#packages").height(height - 60);
  }).resize();
  $("a").live("click", function() {
    var $this = $(this);
    if ($this.hasClass('external')) {
      return true;
    }
    if ($this.parent().hasClass("pkgLink")) {
      $(this).parent().next().slideToggle();
    }
    var href = $this.attr("href");
    if (href != "#") {
      var parts = href.split("#");
      $("#detail").empty().load(parts[0], function() {
        if (parts[1]) {
          var location = $("#"+parts[1]);
          var top = location.position().top - 30;
          $("#detail").scrollTop(top > 0 ? top : 0);
          location.parent().effect("highlight", {}, 1000);
        }
      });
    }
    return false;
  });
  $.get('packages.html').success(function(html) {
    $("#packages").html(html);
    resetPackageLinks();
  }).error(function() {
    showLoadError();
  });
  $("#detail").load("summary.html");

  $(".filterContainer .post").click(filterCleared);
  $("#filter").keyup(function(evt) {
    var filterText = $("#filter").val();
    if (filterText.replace(/^\s+|\s+$/g, '') == "") {
      filterCleared();
    } else {
      var filter = new RegExp(" "+$("#filter").val(), "i")
      $(".pkgContent").each(function(i,e) {
        var $content = $(this);
        var shown = false;
        $(".pkgRow .className", $content).each(function(i, e) {
          var $this = $(this);
          var text = " "+$this.text().replace(".", " ");
          if (filter.test(text)) {
            $this.parents(".pkgRow").show();
            shown = true;
          } else {
            $this.parents(".pkgRow").hide();
          }
        });
        if (shown) {
          $content.show().prev().removeClass("disabled");
        } else {
          $content.hide().prev().addClass("disabled");
        }
      });
    }
  });
});

function filterCleared() {
  $(".pkgLink,.pkgRow").show();
  $(".pkgLink").removeClass("disabled");
  $(".pkgContent").hide();
  resetPackageLinks();
  $("#filter").val("").focus();
}

function resetPackageLinks() {
  var pkgContents = $(".pkgContent");
  if (pkgContents.size() == 1) {
    pkgContents.show();
  }
}

function showLoadError() {
  $('#load-error').show();
  if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1 && document.location.protocol == 'file:') {
    $('#load-error .browser-chrome').show();
  } else {
    $('#load-error .browser-other').show();
  }
}<commit_msg>Fix ff not guessing content type.<commit_after>$(document).ready(function() {
  $(window).resize(function() {
    var height = $(window).height();
    $("#overview").height(height);
    $("#detail").height(height);
    $("#packages").height(height - 60);
  }).resize();
  $("a").live("click", function() {
    var $this = $(this);
    if ($this.hasClass('external')) {
      return true;
    }
    if ($this.parent().hasClass("pkgLink")) {
      $(this).parent().next().slideToggle();
    }
    var href = $this.attr("href");
    if (href != "#") {
      var parts = href.split("#");
      $("#detail").empty().load(parts[0], function() {
        if (parts[1]) {
          var location = $("#"+parts[1]);
          var top = location.position().top - 30;
          $("#detail").scrollTop(top > 0 ? top : 0);
          location.parent().effect("highlight", {}, 1000);
        }
      });
    }
    return false;
  });
  $.get('packages.html', '', function(html) {
    $("#packages").html(html);
    resetPackageLinks();
  }, 'html').error(function() {
    showLoadError();
  });
  $("#detail").load("summary.html");

  $(".filterContainer .post").click(filterCleared);
  $("#filter").keyup(function(evt) {
    var filterText = $("#filter").val();
    if (filterText.replace(/^\s+|\s+$/g, '') == "") {
      filterCleared();
    } else {
      var filter = new RegExp(" "+$("#filter").val(), "i")
      $(".pkgContent").each(function(i,e) {
        var $content = $(this);
        var shown = false;
        $(".pkgRow .className", $content).each(function(i, e) {
          var $this = $(this);
          var text = " "+$this.text().replace(".", " ");
          if (filter.test(text)) {
            $this.parents(".pkgRow").show();
            shown = true;
          } else {
            $this.parents(".pkgRow").hide();
          }
        });
        if (shown) {
          $content.show().prev().removeClass("disabled");
        } else {
          $content.hide().prev().addClass("disabled");
        }
      });
    }
  });
});

function filterCleared() {
  $(".pkgLink,.pkgRow").show();
  $(".pkgLink").removeClass("disabled");
  $(".pkgContent").hide();
  resetPackageLinks();
  $("#filter").val("").focus();
}

function resetPackageLinks() {
  var pkgContents = $(".pkgContent");
  if (pkgContents.size() == 1) {
    pkgContents.show();
  }
}

function showLoadError() {
  $('#load-error').show();
  if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1 && document.location.protocol == 'file:') {
    $('#load-error .browser-chrome').show();
  } else {
    $('#load-error .browser-other').show();
  }
}<|endoftext|>


<commit_before>window.onload = function () {
	// localStorage.getItem('intellect');
	// localStorage.getItem('cunning');
	// localStorage.getItem('acumen');
	$('#char-intellect').html("Intellect: " + localStorage.getItem('intellect'));
	$('#char-cunning').html("Cunning: " + localStorage.getItem('cunning'));
	$('#char-acumen').html("Acumen: " + localStorage.getItem('acumen'));
}

var doorCounter = 0;
var intellect = 0;
var cunning = 0;
var acumen = 0;

// Win conditions: Player will win if he selects all doors without
// triggering an alert || Player has 1/15 chance of winning per door
// checked.

// Lose conditions:  Player has 1/20 chance of tripping an alert
// per door checked.
$('.doors').on('click', function() {
	console.log(this);
	self = this;
	if (doorCounter === 20){
		var youWin = $('
You found the capsule!
');
		$(self).addClass("lastDoor");
		$(youWin).addClass('gotCaught');
		$('body').append(youWin);
	} else if (Math.floor(Math.random()* 20) === 1){
		var gotCaught = $('
Ya got caught, son!
');
		$(self).addClass("wrongDoor");
		$(gotCaught).addClass('gotCaught');
		$('body').append(gotCaught);
		setTimeout($('main').addClass('preposterous'), 5000);
	} else if (Math.floor(Math.random()* 15) === 1){
		var youWin = $('
You found the capsule!
');
		$(self).addClass("lastDoor");
		$(youWin).addClass('gotCaught');
		$('body').append(youWin);
	}
		else {
		$(self).addClass('rightDoor');
		doorCounter++;
	}

});

$('#roll-btn').click(function() {
	var intellectr = Math.floor(Math.random()* 100);
	var cunningr = Math.floor(Math.random()* 100);
	var acumenr = Math.floor(Math.random()* 100);
	$('#intellect').html("Intellect: " + intellectr);
	$('#cunning').html("Cunning: " + cunningr);
	$('#acumen').html("Acumen: " + acumenr);
	return intellect = intellectr, cunning = cunningr, acumen = acumenr;

})
$('#comt-btn').click(function() {
	localStorage.setItem('intellect', intellect);
	localStorage.setItem('cunning', cunning);
	localStorage.setItem('acumen', acumen);
	$('#char-intellect').html("Intellect: " + intellect);
	$('#char-cunning').html("Cunning: " + cunning);
	$('#char-acumen').html("Acumen: " + acumen);
})

$('#charToggle').click(function() {
	$('.characterSheet').slideToggle();
})
// $('html, body').on('click', '.centerheadstone', function() {
// 	$(this).remove();
// 	$('.headstones').removeClass("blurall");
// });
<commit_msg>minor changes<commit_after>window.onload = function () {
	// localStorage.getItem('intellect');
	// localStorage.getItem('cunning');
	// localStorage.getItem('acumen');
	$('#char-intellect').html("Intellect: " + localStorage.getItem('intellect'));
	$('#char-cunning').html("Cunning: " + localStorage.getItem('cunning'));
	$('#char-acumen').html("Acumen: " + localStorage.getItem('acumen'));
}

var doorCounter = 0;

// local variable stats (only relevant on charcreation.html)
var intellect = 0;
var cunning = 0;
var acumen = 0;

// Only relevant for hallgame.html --- Win conditions: Player will win if he selects all doors without
// triggering an alert || Player has 1/15 chance of winning per door
// checked.

// Lose conditions:  Player has 1/20 chance of tripping an alert
// per door checked.
$('.doors').on('click', function() {
	console.log(this);
	self = this;
	if (doorCounter === 20){
		var youWin = $('
You found the capsule!
');
		$(self).addClass("lastDoor");
		$(youWin).addClass('gotCaught');
		$('body').append(youWin);
	} else if (Math.floor(Math.random()* 20) === 1){
		var gotCaught = $('
Ya got caught, son!
');
		$(self).addClass("wrongDoor");
		$(gotCaught).addClass('gotCaught');
		$('body').append(gotCaught);
		setTimeout($('main').addClass('preposterous'), 5000);
	} else if (Math.floor(Math.random()* 15) === 1){
		var youWin = $('
You found the capsule!
');
		$(self).addClass("lastDoor");
		$(youWin).addClass('gotCaught');
		$('body').append(youWin);
	}
		else {
		$(self).addClass('rightDoor');
		doorCounter++;
	}

});

// Generates and displays random character stats
$('#roll-btn').click(function() {
	var intellectr = Math.floor(Math.random()* 100);
	var cunningr = Math.floor(Math.random()* 100);
	var acumenr = Math.floor(Math.random()* 100);
	$('#intellect').html("Intellect: " + intellectr);
	$('#cunning').html("Cunning: " + cunningr);
	$('#acumen').html("Acumen: " + acumenr);
	return intellect = intellectr, cunning = cunningr, acumen = acumenr;

})

// Stores latest roll as character stats
$('#comt-btn').click(function() {
	localStorage.setItem('intellect', intellect);
	localStorage.setItem('cunning', cunning);
	localStorage.setItem('acumen', acumen);
	$('#char-intellect').html("Intellect: " + intellect);
	$('#char-cunning').html("Cunning: " + cunning);
	$('#char-acumen').html("Acumen: " + acumen);
})

// Show's/hides character sheet
$('#charToggle').click(function() {
	$('.characterSheet').slideToggle();
})

var dragSrcEl = null;

function handleDragStart(e) {
  // Target (this) element is the source node.
  this.style.opacity = '0.4';

  dragSrcEl = this;

  e.dataTransfer.effectAllowed = 'move';
  e.dataTransfer.setData('text/html', this.innerHTML);
}
// $('html, body').on('click', '.centerheadstone', function() {
// 	$(this).remove();
// 	$('.headstones').removeClass("blurall");
// });
<|endoftext|>