<commit_before>import React from 'react';
import { Button, Bullseye, GalleryItem, Popover } from '@patternfly/react-core';
import { global_FontSize_sm as labelFontSize } from '@patternfly/react-tokens';
/** @jsx jsx */
import { css, jsx } from '@emotion/core';
import posed from 'react-pose';
import copy from 'clipboard-copy';
import { saveAs } from 'file-saver';
import ReactDOM from 'react-dom';
import { DownloadIcon, CopyrightIcon, ClipboardIcon } from '../../../node_modules/@patternfly/react-icons';

const styles = {
  iconCell: css`
    padding-top: 32px;
    padding-right: 16px;
    padding-bottom: 32px;
    padding-left: 16px;
    // box-shadow: 0 4px 8px 2px rgba(0, 0, 0, 0.12), 0 6px 20px 2px rgba(0, 0, 0, 0.12);
    background-color: rgba(190, 225, 244, 0.5);
    cursor: pointer;
    &:hover {
      background-color: rgba(190, 225, 244, 0.75);
    }
  `,
  textbox: css`
    text-align: center;
    margin: 3px;
    padding-top: 16px;
    overflow: hidden;
  `,
  label: css`
    font-size: 18px;
    word-break: break-all;
  `,
  innerItem: css`
    display: flex;
    flex-direction: column;
    align-items: center;

    > * {
      > * {
        width: 32px;
        height: 32px;
      }
    }
  `,
  labelHovered: css`
    font-size: ${labelFontSize.var};
    word-break: break-all;
    transform: scale(0.7);
  `,
  popover: css`
    width: 500px;
    .pf-c-popover {
      width: 100%;
    }
  `,
  popoverHeader: css`
    margin-right: 10px;
  `,
  popoverBody: css`
    display: flex;
    flex-direction: column;
    align-items: left;
  `,
  textDescription: css`
    margin-bottom: 16px;
  `,
  copyButtons: css`
    display: flex;
    margin-left: -16px;
    button {
      @media only screen and (max-width: 499px) {
        font-size: 14px;
      }
    }
  `,
  scaleDown: css`transform: scale(.7);`,
  openContainer: css`display: flex;`,
  leftContainer: css`
    width: 100px;
    display: flex;
    flex-direction: column;
    color: white;
    padding: 15px 0 0 10px;
    align-items: center;
  `,
  rightContainer: css`
    display: flex;
    flex-direction: column;
    flex: 1;
    transform: scale(0.85);
  `,
  hoveredColor: css`color: white;`
};

const Box = posed.div({
  pressable: true,
  init: { scale: 1 },
  press: { scale: 1.3 }
});

class IconCard extends React.Component {
  constructor(props) {
    super(props);
    this.iconRef = React.createRef();
    this.state = { showBody: false };
    this.galleryItemRef = React.createRef();
    this.galleryItemBodyRef = React.createRef();
    this.handleClickOutside = this.handleClickOutside.bind(this);
  }

  componentDidMount = () => {
    document.addEventListener('click', this.handleClickOutside);
  }

  componentWillUnmount = () => {
    document.removeEventListener('click', this.handleClickOutside);
  }

  handleClickOutside(event) {
    // Little timeout to let the active component's showBody state resolve first
    setTimeout(function() {
      if (this.state.showBody && !this.galleryItemRef.current.contains(event.target) && !this.galleryItemBodyRef.current.contains(event.target)) {
        this.setState({
          showBody: false
        });
      }
    }.bind(this), 10);
  }

  toggleBody = () => {
    this.setState(prevState => ({
      showBody: !prevState.showBody
   }))
  };

  onCopyReact = event => {
    event.stopPropagation();
    const { id } = this.props;
    copy(`import { ${id} } from '@patternfly/react-icons'`);
  };

  onCopyHtml = event => {
    event.stopPropagation();
    const { name } = this.props;
    copy(`<i className="pf-icon pf-icon-${name}"></i>`);
  };

  onDownloadSvg = () => {
    const { name } = this.props;
    const domNode = ReactDOM.findDOMNode(this.iconRef.current);
    domNode.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    domNode.setAttribute("width", "100%");
    domNode.setAttribute("height", "100%");
    const { outerHTML } = domNode;
    const preface = '<?xml version="1.0" standalone="no"?>\r\n';

    const filename = `${name}.svg`;

    const blob = new Blob([preface, outerHTML], {
      type: 'image/svg+xml;charset=utf-8'
    });

    saveAs(blob, filename);
  };

  render() {
    const { icon: Icon, name } = this.props;
    const { showBody } = this.state;
    const popoverBody = (

Indicates that a user may create or add something.

          <Box><Button variant="link" onClick={this.onDownloadSvg}><DownloadIcon /> SVG</Button></Box>
          <Box><Button variant="link" onClick={this.onCopyHtml}><ClipboardIcon /> HTML</Button></Box>
          <Box><Button variant="link" onClick={this.onCopyReact}><ClipboardIcon />React</Button></Box>

    );
    return (
      <>
        <GalleryItem onClick={this.toggleBody}>

              <Bullseye>

                  <Bullseye>
                    {typeof window !== 'undefined' && <Icon size="xl" ref={this.iconRef} />}
                  </Bullseye>

              </Bullseye>

              {name}

        </GalleryItem>
        <GalleryItem style={{display: showBody ? 'block' : 'none', gridColumn: '1 / -1'}}>

            {/*
 */}

              <button className="pf-c-button pf-m-plain" aria-label="Close" onClick={this.toggleBody}>

              </button>

                {name}

                {popoverBody}

        </GalleryItem>
      </>
    );
  }

}

export default IconCard;
<commit_msg>update<commit_after>import React from 'react';
import { Button, Bullseye, GalleryItem, Popover } from '@patternfly/react-core';
import { global_FontSize_sm as labelFontSize } from '@patternfly/react-tokens';
/** @jsx jsx */
import { css, jsx } from '@emotion/core';
import posed from 'react-pose';
import copy from 'clipboard-copy';
import { saveAs } from 'file-saver';
import ReactDOM from 'react-dom';
import { DownloadIcon, ClipboardIcon } from '../../../node_modules/@patternfly/react-icons';

const styles = {
  iconCell: css`
    padding-top: 32px;
    padding-right: 16px;
    padding-bottom: 32px;
    padding-left: 16px;
    // box-shadow: 0 4px 8px 2px rgba(0, 0, 0, 0.12), 0 6px 20px 2px rgba(0, 0, 0, 0.12);
    background-color: rgba(190, 225, 244, 0.5);
    cursor: pointer;
    &:hover {
      background-color: rgba(190, 225, 244, 0.75);
    }
  `,
  textbox: css`
    text-align: center;
    margin: 3px;
    padding-top: 16px;
    overflow: hidden;
  `,
  label: css`
    font-size: 18px;
    word-break: break-all;
  `,
  innerItem: css`
    display: flex;
    flex-direction: column;
    align-items: center;

    > * {
      > * {
        width: 32px;
        height: 32px;
      }
    }
  `,
  labelHovered: css`
    font-size: ${labelFontSize.var};
    word-break: break-all;
    transform: scale(0.7);
  `,
  popover: css`
    width: 500px;
    .pf-c-popover {
      width: 100%;
    }
  `,
  popoverHeader: css`
    margin-right: 10px;
  `,
  popoverBody: css`
    display: flex;
    flex-direction: column;
    align-items: left;
  `,
  textDescription: css`
    margin-bottom: 16px;
  `,
  copyButtons: css`
    display: flex;
    margin-left: -16px;
    button {
      @media only screen and (max-width: 499px) {
        font-size: 14px;
      }
    }
  `,
  scaleDown: css`transform: scale(.7);`,
  openContainer: css`display: flex;`,
  leftContainer: css`
    width: 100px;
    display: flex;
    flex-direction: column;
    color: white;
    padding: 15px 0 0 10px;
    align-items: center;
  `,
  rightContainer: css`
    display: flex;
    flex-direction: column;
    flex: 1;
    transform: scale(0.85);
  `,
  hoveredColor: css`color: white;`
};

const Box = posed.div({
  pressable: true,
  init: { scale: 1 },
  press: { scale: 1.3 }
});

class IconCard extends React.Component {
  constructor(props) {
    super(props);
    this.iconRef = React.createRef();
    this.state = { showBody: false };
    this.galleryItemRef = React.createRef();
    this.galleryItemBodyRef = React.createRef();
    this.handleClickOutside = this.handleClickOutside.bind(this);
  }

  componentDidMount = () => {
    document.addEventListener('click', this.handleClickOutside);
  }

  componentWillUnmount = () => {
    document.removeEventListener('click', this.handleClickOutside);
  }

  handleClickOutside(event) {
    // Little timeout to let the active component's showBody state resolve first
    setTimeout(function() {
      if (this.state.showBody && !this.galleryItemRef.current.contains(event.target) && !this.galleryItemBodyRef.current.contains(event.target)) {
        this.setState({
          showBody: false
        });
      }
    }.bind(this), 10);
  }

  toggleBody = () => {
    this.setState(prevState => ({
      showBody: !prevState.showBody
   }))
  };

  onCopyReact = event => {
    event.stopPropagation();
    const { id } = this.props;
    copy(`import { ${id} } from '@patternfly/react-icons'`);
  };

  onCopyHtml = event => {
    event.stopPropagation();
    const { name } = this.props;
    copy(`<i className="pf-icon pf-icon-${name}"></i>`);
  };

  onDownloadSvg = () => {
    const { name } = this.props;
    const domNode = ReactDOM.findDOMNode(this.iconRef.current);
    domNode.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    domNode.setAttribute("width", "100%");
    domNode.setAttribute("height", "100%");
    const { outerHTML } = domNode;
    const preface = '<?xml version="1.0" standalone="no"?>\r\n';

    const filename = `${name}.svg`;

    const blob = new Blob([preface, outerHTML], {
      type: 'image/svg+xml;charset=utf-8'
    });

    saveAs(blob, filename);
  };

  render() {
    const { icon: Icon, name } = this.props;
    const { showBody } = this.state;
    const popoverBody = (

Indicates that a user may create or add something.

          <Box><Button variant="link" onClick={this.onDownloadSvg}><DownloadIcon /> SVG</Button></Box>
          <Box><Button variant="link" onClick={this.onCopyHtml}><ClipboardIcon /> HTML</Button></Box>
          <Box><Button variant="link" onClick={this.onCopyReact}><ClipboardIcon />React</Button></Box>

    );
    return (
      <>
        <GalleryItem onClick={this.toggleBody}>

              <Bullseye>

                  <Bullseye>
                    {typeof window !== 'undefined' && <Icon size="xl" ref={this.iconRef} />}
                  </Bullseye>

              </Bullseye>

              {name}

        </GalleryItem>
        <GalleryItem style={{display: showBody ? 'block' : 'none', gridColumn: '1 / -1'}}>

            {/*
 */}

              <button className="pf-c-button pf-m-plain" aria-label="Close" onClick={this.toggleBody}>

              </button>

                {name}

                {popoverBody}

        </GalleryItem>
      </>
    );
  }

}

export default IconCard;
<|endoftext|>


<commit_before>/***  HIMLE RIA SYSTEM
  **
  **  Copyright (C) 2008 HIMLE GROUP http://himle.sorsacode.com/
  **  Copyright (C) 2006-2007 Helmi Technologies Inc.
  **
  **  This program 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 2 of the License, or (at your option) any later version.
  **  This program 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 this program;
  **  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  ***/

/** class: HValueManager
  *
  * *Simple value syncronization system.*
  *
  * Designed as single instance, depends on <HValue> and <HControl>.
  *
  * The system relies heavily on <HValue> instances.
  * It allows easy value syncronization between the server and client components.
  * <HTransporter> makes <toXML> calls whenever it's making a server poll to send
  * changed data to the server as XML, accessable by the 'HSyncData' request key.
  *
  * See Also:
  *  <HValue> <HTransporter> <HControl>
  *
  * Simple usage example:
  *  > var myApp = new HApplication(100);
  *  > var myTextCtrl1 = new HTextControl(new HRect(100,100,356,118),myApp,'',"Hello, I'm a textcontrol!");
  *  > myTextCtrl1.draw();
  *  > var myTextCtrl2 = new HTextControl(new HRect(120,100,356,138),myApp,'',"Hi, I'm also a textcontrol!");
  *  > myTextCtrl2.draw();
  *  > var myNewHValue = new HValue('foo123', "Hi, I am an example value.");
  *  > myNewValue.bind( myTextCtrl1 );
  *  > myNewValue.bind( myTextCtrl2 );
  *  > HValueManager.set('foo123',"Hi, I am the new replacement value!");
  *  > var myXMLChanged = HValueManager.toXML();
  **/

HValueManager = HClass.extend({
  constructor: null,

/** vars: Instance variables
  *
  * values - Array, contains all values currently managed, accessible by <HValue> id:s
  * tosync - Array, contains changed values that need to be reported to the remote side via <HTransporter>
  * isSending - flag, is set to true when <HTransporter> is busy.
  *
  **/
  values: {},
  tosync: [],
  isSending: false,
  isGetting: false,

/*** method: add
  **
  ** Adds a new <HValue> bound to the value of id into the value index of <HValueManager>.
  ** These values will then then be automatically syncronized between components
  ** and other compatible instances, like server-side value management. Most
  ** likely to be called from inside a <HValue> constructor.
  **
  ** Parameters:
  **  _id - An id for the value, doesn't really matter at the client-side as long as it is unique. Matters for server-side. Could be int or str, depending on the server implementation.
  **  _obj - A <HValue> object instance, usually *this* inside constructors of <HValue>-compatible classes.
  **
  ** See also:
  **  <set> <del> <HValue.constructor>
  ***/
  add: function(_id,_obj){
    this.values[_id] = _obj;
  },

/*** method: set
  **
  ** Sets a new *container value* to the <HValue> object by calling the bound <HValue> by its id.
  **
  ** Parameters:
  **  _id - The <HValue>-instance id to be modified.
  **  _value - The container value (NOT a <HValue>)
  **
  ** See also:
  **  <add> <del> <HValue.set> <HControl.setValue>
  ***/
  set: function(_id,_value){
    this.values[_id].set(_value);
  },

  s: function(_id,_value){
    this.values[_id].s(_value);
  },

/*** method: del
  **
  ** Deletes the <HValue> by id from the value management system.
  **
  ** Parameters:
  **  _id - The <HValue>-instance id to be deleted.
  **
  ** See also:
  **  <add> <set> <HValue>
  ***/
  del: function(_id){
    var _thisVal  = this.values[_id];
    var _valViews = _thisVal.views;
    for(var _viewNum=0;_viewNum<_valViews.length;_viewNum++){
      var _thisView = _valViews[_viewNum];
      _thisView.valueObj = new HDummyValue(0,_thisVal.value);
    }
    this.values[_id] = null;
  },

/*** method: changed
  **
  ** Reports the <HValue> to <HValueManager> as a changed object.
  ** It adds a reference to the <HValue>, unless the value is changed via <HTransporter>.
  **
  ** There is no need to call it manually, except when creating a new <HValue> -compatible
  ** object from the scratch. Value-classes call changed whenever the change needs
  ** to be reported elsewhere.
  **
  ** Parameters:
  **  _theObj - The <HValue> -instance object to list as changed.
  **
  ** See also:
  **  <isGetting> <tosync> <set>
  ***/
  changed: function(_theObj){
    if(this.isGetting==false){
      if(this.tosync.indexOf(_theObj.id)==-1){
        this.tosync.push(_theObj.id);
      }
      var _t=HTransporter;
      if(!_t.pollMode){
        clearTimeout(_t.req_timeout);
        _t.req_timeout = setTimeout('HTransporter.sync();',_t.syncDelay);
      }
    }
  },

/*** method: toXML
  **
  ** Outputs all changed values to XML.
  **
  ** See also:
  **  <HTransporter>
  ***/
  toXML: function(){
    var _postBody = '&HSyncData=';
    if(!this.isSending){
      this.isSending = true;
      var _synclen = this.tosync.length;
      if(_synclen==0){
        this.isSending = false;
        return '';
      }
      var _syncvalueArr = [],_i;
      for(_i=0;_i<_synclen;_i++){
        var _syncid = this.tosync.shift();
        var _syncobj = this.values[_syncid];
        _syncvalueArr.push( _syncobj.toXML(_i) );
      }
      var _syncvalues = _syncvalueArr.join('');
      // version: 8000 + himle svn revision at modification time
      _postBody += '<hsyncvalues version="8118">'+_syncvalues+'</hsyncvalues>';
      this.isSending = false;
    }
    return _postBody;
  },

  // Backwards-compatibility:
  output: function(){
    return this.toXML();
  }
});

// HVM is a shortcut to HValueManager
HVM = HValueManager;

<commit_msg>tidied up a part of HValueManager, no functionality changed<commit_after>/***  HIMLE RIA SYSTEM
  **
  **  Copyright (C) 2008 HIMLE GROUP http://himle.sorsacode.com/
  **  Copyright (C) 2006-2007 Helmi Technologies Inc.
  **
  **  This program 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 2 of the License, or (at your option) any later version.
  **  This program 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 this program;
  **  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  ***/

/** class: HValueManager
  *
  * *Simple value syncronization system.*
  *
  * Designed as single instance, depends on <HValue> and <HControl>.
  *
  * The system relies heavily on <HValue> instances.
  * It allows easy value syncronization between the server and client components.
  * <HTransporter> makes <toXML> calls whenever it's making a server poll to send
  * changed data to the server as XML, accessable by the 'HSyncData' request key.
  *
  * See Also:
  *  <HValue> <HTransporter> <HControl>
  *
  * Simple usage example:
  *  > var myApp = new HApplication(100);
  *  > var myTextCtrl1 = new HTextControl(new HRect(100,100,356,118),myApp,'',"Hello, I'm a textcontrol!");
  *  > myTextCtrl1.draw();
  *  > var myTextCtrl2 = new HTextControl(new HRect(120,100,356,138),myApp,'',"Hi, I'm also a textcontrol!");
  *  > myTextCtrl2.draw();
  *  > var myNewHValue = new HValue('foo123', "Hi, I am an example value.");
  *  > myNewValue.bind( myTextCtrl1 );
  *  > myNewValue.bind( myTextCtrl2 );
  *  > HValueManager.set('foo123',"Hi, I am the new replacement value!");
  *  > var myXMLChanged = HValueManager.toXML();
  **/

HValueManager = HClass.extend({
  constructor: null,

/** vars: Instance variables
  *
  * values - Array, contains all values currently managed, accessible by <HValue> id:s
  * tosync - Array, contains changed values that need to be reported to the remote side via <HTransporter>
  * isSending - flag, is set to true when <HTransporter> is busy.
  *
  **/
  values: {},
  tosync: [],
  isSending: false,
  isGetting: false,

/*** method: add
  **
  ** Adds a new <HValue> bound to the value of id into the value index of <HValueManager>.
  ** These values will then then be automatically syncronized between components
  ** and other compatible instances, like server-side value management. Most
  ** likely to be called from inside a <HValue> constructor.
  **
  ** Parameters:
  **  _id - An id for the value, doesn't really matter at the client-side as long as it is unique. Matters for server-side. Could be int or str, depending on the server implementation.
  **  _obj - A <HValue> object instance, usually *this* inside constructors of <HValue>-compatible classes.
  **
  ** See also:
  **  <set> <del> <HValue.constructor>
  ***/
  add: function(_id,_obj){
    this.values[_id] = _obj;
  },

/*** method: set
  **
  ** Sets a new *container value* to the <HValue> object by calling the bound <HValue> by its id.
  **
  ** Parameters:
  **  _id - The <HValue>-instance id to be modified.
  **  _value - The container value (NOT a <HValue>)
  **
  ** See also:
  **  <add> <del> <HValue.set> <HControl.setValue>
  ***/
  set: function(_id,_value){
    this.values[_id].set(_value);
  },

  s: function(_id,_value){
    this.values[_id].s(_value);
  },

/*** method: del
  **
  ** Deletes the <HValue> by id from the value management system.
  **
  ** Parameters:
  **  _id - The <HValue>-instance id to be deleted.
  **
  ** See also:
  **  <add> <set> <HValue>
  ***/
  del: function(_id){
    var _thisVal  = this.values[_id],
        _valViews = _thisVal.views,
        _viewNum  = 0,
        _thisView = null;
    for(;_viewNum<_valViews.length;_viewNum++){
      _thisView = _valViews[_viewNum];
      _thisView.valueObj = new HDummyValue(0,_thisVal.value);
    }
    this.values[_id] = null;
  },

/*** method: changed
  **
  ** Reports the <HValue> to <HValueManager> as a changed object.
  ** It adds a reference to the <HValue>, unless the value is changed via <HTransporter>.
  **
  ** There is no need to call it manually, except when creating a new <HValue> -compatible
  ** object from the scratch. Value-classes call changed whenever the change needs
  ** to be reported elsewhere.
  **
  ** Parameters:
  **  _theObj - The <HValue> -instance object to list as changed.
  **
  ** See also:
  **  <isGetting> <tosync> <set>
  ***/
  changed: function(_theObj){
    if(this.isGetting==false){
      if(this.tosync.indexOf(_theObj.id)==-1){
        this.tosync.push(_theObj.id);
      }
      var _t=HTransporter;
      if(!_t.pollMode){
        clearTimeout(_t.req_timeout);
        _t.req_timeout = setTimeout('HTransporter.sync();',_t.syncDelay);
      }
    }
  },

/*** method: toXML
  **
  ** Outputs all changed values to XML.
  **
  ** See also:
  **  <HTransporter>
  ***/
  toXML: function(){
    var _postBody = '&HSyncData=';
    if(!this.isSending){
      this.isSending = true;
      var _synclen = this.tosync.length;
      if(_synclen==0){
        this.isSending = false;
        return '';
      }
      var _syncvalueArr = [],_i;
      for(_i=0;_i<_synclen;_i++){
        var _syncid = this.tosync.shift();
        var _syncobj = this.values[_syncid];
        _syncvalueArr.push( _syncobj.toXML(_i) );
      }
      var _syncvalues = _syncvalueArr.join('');
      // version: 8000 + himle svn revision at modification time
      _postBody += '<hsyncvalues version="8118">'+_syncvalues+'</hsyncvalues>';
      this.isSending = false;
    }
    return _postBody;
  },

  // Backwards-compatibility:
  output: function(){
    return this.toXML();
  }
});

// HVM is a shortcut to HValueManager
HVM = HValueManager;

<|endoftext|>


<commit_before>//
// Copyright (C) 2013 - present Instructure, Inc.
//
// This file is part of Canvas.
//
// Canvas is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
// Software Foundation, version 3 of the License.
//
// Canvas 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 Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.

import I18n from 'i18n!course_navigation'
import $ from 'jquery'
import Backbone from '@canvas/backbone'
import {reorderElements, renderTray} from '@canvas/move-item-tray'
/*
xsslint jqueryObject.identifier dragObject current_item
*/

export default class NavigationView extends Backbone.View {
  static initClass() {
    this.prototype.events = {
      'click .disable_nav_item_link': 'disableNavLink',
      'click .move_nav_item_link': 'moveNavLink',
      'click .enable_nav_item_link': 'enableNavLink'
    }

    this.prototype.els = {
      '#nav_enabled_list': '$enabled_list',
      '#nav_disabled_list': '$disabled_list',
      '.navitem': '$navitems'
    }
  }

  disableNavLink(e) {
    const $targetItem = $(e.currentTarget).closest('.navitem')
    this.$disabled_list.append($targetItem)
    $(e.currentTarget)
      .attr('class', '')
      .attr('class', 'icon-plus enable_nav_item_link')
      .text('Enable')
    return $targetItem.find('a.al-trigger').focus()
  }

  enableNavLink(e) {
    const $targetItem = $(e.currentTarget).closest('.navitem')
    this.$enabled_list.append($targetItem)
    $(e.currentTarget)
      .attr('class', '')
      .attr('class', 'icon-x disable_nav_item_link')
      .text('Disable')
    return $targetItem.find('a.al-trigger').focus()
  }

  moveNavLink(e) {
    const selectedItem = $(e.currentTarget).closest('.navitem')
    const navList = $(e.currentTarget).closest('.nav_list')
    const navOptions = navList
      .children('.navitem')
      .map((key, item) => ({
        id: item.getAttribute('id'),
        title: item.getAttribute('aria-label')
      }))
      .toArray()

    this.moveTrayProps = {
      title: I18n.t('Move Navigation Item'),
      items: [
        {
          id: selectedItem.attr('id'),
          title: selectedItem.attr('aria-label')
        }
      ],
      moveOptions: {
        siblings: navOptions
      },
      onMoveSuccess: res => reorderElements(res.data, this.$enabled_list[0], id => `#${id}`),
      focusOnExit: item => document.querySelector(`#${item.id} a.al-trigger`)
    }

    return renderTray(this.moveTrayProps, document.getElementById('not_right_side'))
  }

  focusKeyboardHelp(e) {
    $('.drag_and_drop_warning').removeClass('screenreader-only')
  }

  hideKeyboardHelp(e) {
    $('.drag_and_drop_warning').addClass('screenreader-only')
  }

  afterRender() {
    $('#navigation_tab').on('blur', this.focusKeyboardHelp)
    $('.drag_and_drop_warning').on('blur', this.hideKeyboardHelp)
  }
}
NavigationView.initClass()
<commit_msg>A11y Warning should appear only when using keyboard navigation<commit_after>//
// Copyright (C) 2013 - present Instructure, Inc.
//
// This file is part of Canvas.
//
// Canvas is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
// Software Foundation, version 3 of the License.
//
// Canvas 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 Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.

import I18n from 'i18n!course_navigation'
import $ from 'jquery'
import Backbone from '@canvas/backbone'
import {reorderElements, renderTray} from '@canvas/move-item-tray'
/*
xsslint jqueryObject.identifier dragObject current_item
*/

export default class NavigationView extends Backbone.View {
  static initClass() {
    this.prototype.events = {
      'click .disable_nav_item_link': 'disableNavLink',
      'click .move_nav_item_link': 'moveNavLink',
      'click .enable_nav_item_link': 'enableNavLink'
    }

    this.prototype.els = {
      '#nav_enabled_list': '$enabled_list',
      '#nav_disabled_list': '$disabled_list',
      '.navitem': '$navitems'
    }
  }

  disableNavLink(e) {
    const $targetItem = $(e.currentTarget).closest('.navitem')
    this.$disabled_list.append($targetItem)
    $(e.currentTarget)
      .attr('class', '')
      .attr('class', 'icon-plus enable_nav_item_link')
      .text('Enable')
    return $targetItem.find('a.al-trigger').focus()
  }

  enableNavLink(e) {
    const $targetItem = $(e.currentTarget).closest('.navitem')
    this.$enabled_list.append($targetItem)
    $(e.currentTarget)
      .attr('class', '')
      .attr('class', 'icon-x disable_nav_item_link')
      .text('Disable')
    return $targetItem.find('a.al-trigger').focus()
  }

  moveNavLink(e) {
    const selectedItem = $(e.currentTarget).closest('.navitem')
    const navList = $(e.currentTarget).closest('.nav_list')
    const navOptions = navList
      .children('.navitem')
      .map((key, item) => ({
        id: item.getAttribute('id'),
        title: item.getAttribute('aria-label')
      }))
      .toArray()

    this.moveTrayProps = {
      title: I18n.t('Move Navigation Item'),
      items: [
        {
          id: selectedItem.attr('id'),
          title: selectedItem.attr('aria-label')
        }
      ],
      moveOptions: {
        siblings: navOptions
      },
      onMoveSuccess: res => reorderElements(res.data, this.$enabled_list[0], id => `#${id}`),
      focusOnExit: item => document.querySelector(`#${item.id} a.al-trigger`)
    }

    return renderTray(this.moveTrayProps, document.getElementById('not_right_side'))
  }

  resetReadState(e) {
    $('.drag_and_drop_warning').removeClass('read')
  }

  focusKeyboardHelp(e) {
    if (!$('.drag_and_drop_warning').hasClass('read')) {
      $('.drag_and_drop_warning').removeClass('screenreader-only')
    }
  }

  hideKeyboardHelp(e) {
    $('.drag_and_drop_warning').addClass('screenreader-only read')
  }

  afterRender() {
    $('#navigation_tab').on('blur', this.resetReadState)
    $('#tab-navigation').on('keyup', this.focusKeyboardHelp)
    $('.drag_and_drop_warning').on('blur', this.hideKeyboardHelp)
  }
}
NavigationView.initClass()
<|endoftext|>


<commit_before>/*
===============================================================================================

		Unify Project

		Homepage: unify-project.org
		License: MIT + Apache (V2)
		Copyright: 2012, Sebastian Fastner, Mainz, Germany, http://unify-training.com

===============================================================================================
*/

/**
 * #break(unify.ui.layout.queue.Manager)
 */

(function() {

	var widgetQueue = [];

	/** {String} Name of queue */
	var name = "layout";

	var sortWidgets = function(a,b) {
		if (!a) {
			return 1;
		}
		if (!b) {
			return -1;
		}
		return a.getNestingLevel() - b.getNestingLevel();
	};

	core.Module("unify.ui.layout.queue.Layout", {
		name : name,

		/**
		 * Add @widget {unify.ui.core.Widget} to queue.
		 */
		add : function(widget) {
			if (!core.Array.contains(widgetQueue, widget)) {
				widgetQueue.push(widget);
				unify.ui.layout.queue.Manager.run(name);
			}
		},

		remove : function(widget) {
			widgetQueue.remove(widget);
		},

		/**
		 * Flushes queue.
		 */
		flush : function() {
			widgetQueue.sort(sortWidgets);
			for (var i=0,ii=widgetQueue.length; i<ii; i++) {
				for (var j=i-1;j>=0;j--) {
					if (widgetQueue[i] === widgetQueue[j]) {
						widgetQueue[i]  = null;
					}
				}
			}

			var widget;
			while ((widget = widgetQueue.shift())) {
				var bounds = widget.getBounds();

				if (bounds) {
					widget.renderLayout(bounds.left, bounds.top, bounds.width, bounds.height);
				}
			}
		}
	});

})();
<commit_msg>Fix remove from array in layouting queue<commit_after>/*
===============================================================================================

		Unify Project

		Homepage: unify-project.org
		License: MIT + Apache (V2)
		Copyright: 2012, Sebastian Fastner, Mainz, Germany, http://unify-training.com

===============================================================================================
*/

/**
 * #break(unify.ui.layout.queue.Manager)
 */

(function() {

	var widgetQueue = [];

	/** {String} Name of queue */
	var name = "layout";

	var sortWidgets = function(a,b) {
		if (!a) {
			return 1;
		}
		if (!b) {
			return -1;
		}
		return a.getNestingLevel() - b.getNestingLevel();
	};

	core.Module("unify.ui.layout.queue.Layout", {
		name : name,

		/**
		 * Add @widget {unify.ui.core.Widget} to queue.
		 */
		add : function(widget) {
			if (!core.Array.contains(widgetQueue, widget)) {
				widgetQueue.push(widget);
				unify.ui.layout.queue.Manager.run(name);
			}
		},

		remove : function(widget) {
			core.Array.remove(widgetQueue, widget);
		},

		/**
		 * Flushes queue.
		 */
		flush : function() {
			widgetQueue.sort(sortWidgets);
			for (var i=0,ii=widgetQueue.length; i<ii; i++) {
				for (var j=i-1;j>=0;j--) {
					if (widgetQueue[i] === widgetQueue[j]) {
						widgetQueue[i]  = null;
					}
				}
			}

			var widget;
			while ((widget = widgetQueue.shift())) {
				var bounds = widget.getBounds();

				if (bounds) {
					widget.renderLayout(bounds.left, bounds.top, bounds.width, bounds.height);
				}
			}
		}
	});

})();
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { withProps } from 'recompose';

import Loader from '../Loader';

import TableStyles from './styles/TableStyles';
import TableOverlay from './styles/TableOverlay';

import Cell from './styles/TableCell';
import Header from './TableHeader';
import Row from './styles/TableRow';
import Controls from './TableControls';
import Simple from './SimpleTable';
import RowDetails from './TableRowDetails';
import TableWrap from './TableWrap';
import TableBody from './styles/TableBody';

class Table extends React.Component {
  static propTypes = {
    /**
     * Render the rows of the Table within its children.
     */
    children: PropTypes.node.isRequired,
    /**
     * Render headers for the columns with this property.
     */
    headers: PropTypes.node,
    /**
     * Renders a loading spinner over the table body.
     */
    loading: PropTypes.bool,
    /**
     * Adds a class name to the table element.
     */
    className: PropTypes.string,
    /**
     * Adds an id to the table element.
     */
    id: PropTypes.string,
    /**
     * Whether to wrap the passed children in a
. Defaults true.
     */
    wrapBody: PropTypes.bool,
    /**
     * A component to render the table element
     */
    Styles: PropTypes.func,
    /**
     * A component to render any content that overlays the table itself
     */
    Overlay: PropTypes.func,
    /**
     * A component that wraps the whole table as a scroll context
     */
    Wrap: PropTypes.func,
  };

  static defaultProps = {
    loading: false,
    className: null,
    id: null,
    headers: null,
    wrapBody: true,
    Styles: TableStyles,
    Overlay: TableOverlay,
    Wrap: TableWrap,
  };

  render() {
    const {
      children,
      headers,
      loading,
      wrapBody,
      Wrap,
      Styles,
      Overlay,
      ...rest
    } = this.props;
    return (
      <Wrap>

        {loading && (
          <Overlay>
            <Loader />
          </Overlay>
        )}
      </Wrap>
    );
  }
}

Table.Row = Row;
Table.Header = Header;
Table.Cell = Cell;
Table.Controls = Controls;
Table.Simple = Simple;
Table.RowDetails = RowDetails;
Table.Wrap = TableWrap;
Table.Body = TableBody;

Table.Small = withProps({
  Styles: TableStyles.Small,
})(Table);

export default Table;
<commit_msg>force ci<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { withProps } from 'recompose';

import Loader from '../Loader';

import TableStyles from './styles/TableStyles';
import TableOverlay from './styles/TableOverlay';

import Cell from './styles/TableCell';
import Header from './TableHeader';
import Row from './styles/TableRow';
import Controls from './TableControls';
import Simple from './SimpleTable';
import RowDetails from './TableRowDetails';
import TableWrap from './TableWrap';
import TableBody from './styles/TableBody';

class Table extends React.Component {
  static propTypes = {
    /**
     * Render the rows of the Table within its children.
     */
    children: PropTypes.node.isRequired,
    /**
     * Render headers for the columns with this property.
     */
    headers: PropTypes.node,
    /**
     * Renders a loading spinner over the table body.
     */
    loading: PropTypes.bool,
    /**
     * Adds a class name to the table element.
     */
    className: PropTypes.string,
    /**
     * Adds an id to the table element.
     */
    id: PropTypes.string,
    /**
     * Whether to wrap the passed children in a
. Defaults true.
     */
    wrapBody: PropTypes.bool,
    /**
     * A component to render the table element
     */
    Styles: PropTypes.func,
    /**
     * A component to render any content that overlays the table itself
     */
    Overlay: PropTypes.func,
    /**
     * A component that wraps the whole table as a scroll context
     */
    Wrap: PropTypes.func,
  };

  static defaultProps = {
    loading: false,
    className: null,
    id: null,
    headers: null,
    wrapBody: true,
    Styles: TableStyles,
    Overlay: TableOverlay,
    Wrap: TableWrap,
  };

  render() {
    const {
      children,
      loading,
      headers,
      wrapBody,
      Wrap,
      Styles,
      Overlay,
      ...rest
    } = this.props;
    return (
      <Wrap>

        {loading && (
          <Overlay>
            <Loader />
          </Overlay>
        )}
      </Wrap>
    );
  }
}

Table.Row = Row;
Table.Header = Header;
Table.Cell = Cell;
Table.Controls = Controls;
Table.Simple = Simple;
Table.RowDetails = RowDetails;
Table.Wrap = TableWrap;
Table.Body = TableBody;

Table.Small = withProps({
  Styles: TableStyles.Small,
})(Table);

export default Table;
<|endoftext|>


<commit_before>/**
 *
 * (c) Copyright Ascensio System SIA 2020
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

var path = require("path");
var urlModule = require("url");
var urllib = require("urllib");
var jwt = require("jsonwebtoken");
var jwa = require("jwa");
var fileUtility = require("./fileUtility");
var guidManager = require("./guidManager");
var configServer = require('config').get('server');
var siteUrl = configServer.get('siteUrl');
var cfgSignatureEnable = configServer.get('token.enable');
var cfgSignatureUseForRequest = configServer.get('token.useforrequest');
var cfgSignatureAuthorizationHeader = configServer.get('token.authorizationHeader');
var cfgSignatureAuthorizationHeaderPrefix = configServer.get('token.authorizationHeaderPrefix');
var cfgSignatureSecretExpiresIn = configServer.get('token.expiresIn');
var cfgSignatureSecret = configServer.get('token.secret');
var cfgSignatureSecretAlgorithmRequest = configServer.get('token.algorithmRequest');

var documentService = {};

documentService.userIp = null;

documentService.getConvertedUriSync = function (documentUri, fromExtension, toExtension, documentRevisionId, callback) {
    documentService.getConvertedUri(documentUri, fromExtension, toExtension, documentRevisionId, false, function (err, data) {
        if (err) {
            callback();
            return;
        }
        var res = documentService.getResponseUri(data);
        callback(res.value);
    });
};

documentService.getConvertedUri = function (documentUri, fromExtension, toExtension, documentRevisionId, async, callback) {
    fromExtension = fromExtension || fileUtility.getFileExtension(documentUri);

    var title = fileUtility.getFileName(documentUri) || guidManager.newGuid();

    documentRevisionId = documentService.generateRevisionId(documentRevisionId || documentUri);

    var params = {
        async: async,
        url: documentUri,
        outputtype: toExtension.replace(".", ""),
        filetype: fromExtension.replace(".", ""),
        title: title,
        key: documentRevisionId
    };

    var uri = siteUrl + configServer.get('converterUrl');
    var headers = {
        'Content-Type': 'application/json',
        "Accept": "application/json"
    };

    if (cfgSignatureEnable && cfgSignatureUseForRequest) {
        headers[cfgSignatureAuthorizationHeader] = cfgSignatureAuthorizationHeaderPrefix + this.fillJwtByUrl(uri, params);
        params.token = documentService.getToken(params);
    }

    urllib.request(uri,
        {
            method: "POST",
            headers: headers,
            data: params
        },
        callback);
};

documentService.generateRevisionId = function (expectedKey) {
    let maxKeyLength = 128;
    if (expectedKey.length > maxKeyLength) {
        expectedKey = expectedKey.hashCode().toString();
    }

    var key = expectedKey.replace(new RegExp("[^0-9-.a-zA-Z_=]", "g"), "_");

    return key.substring(0, Math.min(key.length, maxKeyLength));
};

documentService.processConvertServiceResponceError = function (errorCode) {
    var errorMessage = "";
    var errorMessageTemplate = "Error occurred in the ConvertService: ";

    switch (errorCode) {
        case -20:
            errorMessage = errorMessageTemplate + "Error encrypt signature";
            break;
        case -8:
            errorMessage = errorMessageTemplate + "Error document signature";
            break;
        case -7:
            errorMessage = errorMessageTemplate + "Error document request";
            break;
        case -6:
            errorMessage = errorMessageTemplate + "Error database";
            break;
        case -5:
            errorMessage = errorMessageTemplate + "Error unexpected guid";
            break;
        case -4:
            errorMessage = errorMessageTemplate + "Error download error";
            break;
        case -3:
            errorMessage = errorMessageTemplate + "Error convertation error";
            break;
        case -2:
            errorMessage = errorMessageTemplate + "Error convertation timeout";
            break;
        case -1:
            errorMessage = errorMessageTemplate + "Error convertation unknown";
            break;
        case 0:
            break;
        default:
            errorMessage = "ErrorCode = " + errorCode;
            break;
    }

    throw { message: errorMessage };
};

documentService.getResponseUri = function (json) {
    var fileResult = JSON.parse(json);

    if (fileResult.error)
        documentService.processConvertServiceResponceError(parseInt(fileResult.error));

    var isEndConvert = fileResult.endConvert

    var percent = parseInt(fileResult.percent);
    var uri = null;

    if (isEndConvert) {
        if (!fileResult.fileUrl)
            throw { message: "FileUrl is null" };

        uri = fileResult.fileUrl;
        percent = 100;
    } else {
        percent = percent >= 100 ? 99 : percent;
    }

    return {
        key: percent,
        value: uri
    };
};

documentService.commandRequest = function (method, documentRevisionId, callback) {
    documentRevisionId = documentService.generateRevisionId(documentRevisionId);
    var params = {
        c: method,
        key: documentRevisionId
    };

    var uri = siteUrl + configServer.get('commandUrl');
    var headers = {
        'Content-Type': 'application/json'
    };
    if (cfgSignatureEnable && cfgSignatureUseForRequest) {
        headers[cfgSignatureAuthorizationHeader] = cfgSignatureAuthorizationHeaderPrefix + this.fillJwtByUrl(uri, params);
        params.token = documentService.getToken(params);
    }

    urllib.request(uri,
        {
            method: "POST",
            headers: headers,
            data: params
        },
        callback);
};

documentService.checkJwtHeader = function (req) {
  var decoded = null;
  var authorization = req.get(cfgSignatureAuthorizationHeader);
  if (authorization && authorization.startsWith(cfgSignatureAuthorizationHeaderPrefix)) {
    var token = authorization.substring(cfgSignatureAuthorizationHeaderPrefix.length);
    try {
      decoded = jwt.verify(token, cfgSignatureSecret);
    } catch (err) {
        console.log('checkJwtHeader error: name = ' + err.name + ' message = ' + err.message + ' token = ' + token)
    }
  }
  return decoded;
}

documentService.fillJwtByUrl = function (uri, opt_dataObject) {
  var parseObject = urlModule.parse(uri, true);
  var payload = {query: parseObject.query, payload: opt_dataObject};

  var options = {algorithm: cfgSignatureSecretAlgorithmRequest, expiresIn: cfgSignatureSecretExpiresIn};
  return jwt.sign(payload, cfgSignatureSecret, options);
}

documentService.getToken = function (data) {
    var options = {algorithm: cfgSignatureSecretAlgorithmRequest, expiresIn: cfgSignatureSecretExpiresIn};
    return jwt.sign(data, cfgSignatureSecret, options);
};

documentService.readToken = function (token) {
    try {
        return jwt.verify(token, cfgSignatureSecret);
    } catch (err) {
        console.log('checkJwtHeader error: name = ' + err.name + ' message = ' + err.message + ' token = ' + token)
    }
    return null;
};

module.exports = documentService;
<commit_msg>[bug] Fix invalid request to relative url after changing urllib version to 2.36.1<commit_after>/**
 *
 * (c) Copyright Ascensio System SIA 2020
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

var path = require("path");
var urlModule = require("url");
var urllib = require("urllib");
var jwt = require("jsonwebtoken");
var jwa = require("jwa");
var fileUtility = require("./fileUtility");
var guidManager = require("./guidManager");
var configServer = require('config').get('server');
var siteUrl = configServer.get('siteUrl');
var cfgSignatureEnable = configServer.get('token.enable');
var cfgSignatureUseForRequest = configServer.get('token.useforrequest');
var cfgSignatureAuthorizationHeader = configServer.get('token.authorizationHeader');
var cfgSignatureAuthorizationHeaderPrefix = configServer.get('token.authorizationHeaderPrefix');
var cfgSignatureSecretExpiresIn = configServer.get('token.expiresIn');
var cfgSignatureSecret = configServer.get('token.secret');
var cfgSignatureSecretAlgorithmRequest = configServer.get('token.algorithmRequest');

var documentService = {};

documentService.userIp = null;

documentService.getConvertedUriSync = function (documentUri, fromExtension, toExtension, documentRevisionId, callback) {
    documentService.getConvertedUri(documentUri, fromExtension, toExtension, documentRevisionId, false, function (err, data) {
        if (err) {
            callback();
            return;
        }
        var res = documentService.getResponseUri(data);
        callback(res.value);
    });
};

documentService.getConvertedUri = function (documentUri, fromExtension, toExtension, documentRevisionId, async, callback) {
    fromExtension = fromExtension || fileUtility.getFileExtension(documentUri);

    var title = fileUtility.getFileName(documentUri) || guidManager.newGuid();

    documentRevisionId = documentService.generateRevisionId(documentRevisionId || documentUri);

    var params = {
        async: async,
        url: documentUri,
        outputtype: toExtension.replace(".", ""),
        filetype: fromExtension.replace(".", ""),
        title: title,
        key: documentRevisionId
    };

    var uri = siteUrl + configServer.get('converterUrl');
    var headers = {
        'Content-Type': 'application/json',
        "Accept": "application/json"
    };

    if (cfgSignatureEnable && cfgSignatureUseForRequest) {
        headers[cfgSignatureAuthorizationHeader] = cfgSignatureAuthorizationHeaderPrefix + this.fillJwtByUrl(uri, params);
        params.token = documentService.getToken(params);
    }

    //parse url to allow request by relative url after https://github.com/node-modules/urllib/pull/321/commits/514de1924bf17a38a6c2db2a22a6bc3494c0a959
    urllib.request(urlModule.parse(uri),
        {
            method: "POST",
            headers: headers,
            data: params
        },
        callback);
};

documentService.generateRevisionId = function (expectedKey) {
    let maxKeyLength = 128;
    if (expectedKey.length > maxKeyLength) {
        expectedKey = expectedKey.hashCode().toString();
    }

    var key = expectedKey.replace(new RegExp("[^0-9-.a-zA-Z_=]", "g"), "_");

    return key.substring(0, Math.min(key.length, maxKeyLength));
};

documentService.processConvertServiceResponceError = function (errorCode) {
    var errorMessage = "";
    var errorMessageTemplate = "Error occurred in the ConvertService: ";

    switch (errorCode) {
        case -20:
            errorMessage = errorMessageTemplate + "Error encrypt signature";
            break;
        case -8:
            errorMessage = errorMessageTemplate + "Error document signature";
            break;
        case -7:
            errorMessage = errorMessageTemplate + "Error document request";
            break;
        case -6:
            errorMessage = errorMessageTemplate + "Error database";
            break;
        case -5:
            errorMessage = errorMessageTemplate + "Error unexpected guid";
            break;
        case -4:
            errorMessage = errorMessageTemplate + "Error download error";
            break;
        case -3:
            errorMessage = errorMessageTemplate + "Error convertation error";
            break;
        case -2:
            errorMessage = errorMessageTemplate + "Error convertation timeout";
            break;
        case -1:
            errorMessage = errorMessageTemplate + "Error convertation unknown";
            break;
        case 0:
            break;
        default:
            errorMessage = "ErrorCode = " + errorCode;
            break;
    }

    throw { message: errorMessage };
};

documentService.getResponseUri = function (json) {
    var fileResult = JSON.parse(json);

    if (fileResult.error)
        documentService.processConvertServiceResponceError(parseInt(fileResult.error));

    var isEndConvert = fileResult.endConvert

    var percent = parseInt(fileResult.percent);
    var uri = null;

    if (isEndConvert) {
        if (!fileResult.fileUrl)
            throw { message: "FileUrl is null" };

        uri = fileResult.fileUrl;
        percent = 100;
    } else {
        percent = percent >= 100 ? 99 : percent;
    }

    return {
        key: percent,
        value: uri
    };
};

documentService.commandRequest = function (method, documentRevisionId, callback) {
    documentRevisionId = documentService.generateRevisionId(documentRevisionId);
    var params = {
        c: method,
        key: documentRevisionId
    };

    var uri = siteUrl + configServer.get('commandUrl');
    var headers = {
        'Content-Type': 'application/json'
    };
    if (cfgSignatureEnable && cfgSignatureUseForRequest) {
        headers[cfgSignatureAuthorizationHeader] = cfgSignatureAuthorizationHeaderPrefix + this.fillJwtByUrl(uri, params);
        params.token = documentService.getToken(params);
    }

    //parse url to allow request by relative url after https://github.com/node-modules/urllib/pull/321/commits/514de1924bf17a38a6c2db2a22a6bc3494c0a959
    urllib.request(urlModule.parse(uri),
        {
            method: "POST",
            headers: headers,
            data: params
        },
        callback);
};

documentService.checkJwtHeader = function (req) {
  var decoded = null;
  var authorization = req.get(cfgSignatureAuthorizationHeader);
  if (authorization && authorization.startsWith(cfgSignatureAuthorizationHeaderPrefix)) {
    var token = authorization.substring(cfgSignatureAuthorizationHeaderPrefix.length);
    try {
      decoded = jwt.verify(token, cfgSignatureSecret);
    } catch (err) {
        console.log('checkJwtHeader error: name = ' + err.name + ' message = ' + err.message + ' token = ' + token)
    }
  }
  return decoded;
}

documentService.fillJwtByUrl = function (uri, opt_dataObject) {
  var parseObject = urlModule.parse(uri, true);
  var payload = {query: parseObject.query, payload: opt_dataObject};

  var options = {algorithm: cfgSignatureSecretAlgorithmRequest, expiresIn: cfgSignatureSecretExpiresIn};
  return jwt.sign(payload, cfgSignatureSecret, options);
}

documentService.getToken = function (data) {
    var options = {algorithm: cfgSignatureSecretAlgorithmRequest, expiresIn: cfgSignatureSecretExpiresIn};
    return jwt.sign(data, cfgSignatureSecret, options);
};

documentService.readToken = function (token) {
    try {
        return jwt.verify(token, cfgSignatureSecret);
    } catch (err) {
        console.log('checkJwtHeader error: name = ' + err.name + ' message = ' + err.message + ' token = ' + token)
    }
    return null;
};

module.exports = documentService;
<|endoftext|>


<commit_before>/**
 * Pimcore
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.pimcore.org/license
 *
 * @copyright  Copyright (c) 2009-2014 pimcore GmbH (http://www.pimcore.org)
 * @license    http://www.pimcore.org/license     New BSD License
 */

pimcore.registerNS("pimcore.object.tags.localizedfields");
pimcore.object.tags.localizedfields = Class.create(pimcore.object.tags.abstract, {

    type: "localizedfields",

    frontendLanguages: null,

    initialize: function (data, fieldConfig) {

        this.data = {};
        this.metaData = {};
        this.inherited = false;
        this.languageElements = {};
        this.inheritedFields = {};
        this.referencedFields = [];
        this.availablePanels = [];
        this.dropdownLayout = false;

        if (pimcore.currentuser.admin || fieldConfig.permissionView === undefined) {
            this.frontendLanguages = pimcore.settings.websiteLanguages;
        } else {
            this.frontendLanguages = fieldConfig.permissionView;
        }

        var maxTabs = 15;
        if (typeof fieldConfig.maxTabs == "number") {
            maxTabs = fieldConfig.maxTabs;
        }

        if (this.frontendLanguages.length > maxTabs) {
            this.dropdownLayout = true;
        }

        if (data) {
            if (data.data) {
                this.data = data.data;
            }
            if (data.metaData) {
                this.metaData = data.metaData;
            }
            if (data.inherited) {
                this.inherited = data.inherited;
            }
        }
        this.fieldConfig = fieldConfig;

        this.keysToWatch = [];

        if (this.inherited) {
            for (var i=0; i < this.frontendLanguages.length; i++) {
                var currentLanguage = this.frontendLanguages[i];

                var metadataForLanguage = this.metaData[currentLanguage];
                var dataKeys = Object.keys(metadataForLanguage);

                for (var k = 0; k < dataKeys.length; k++) {
                    var dataKey = dataKeys[k];
                    var metadataForKey = metadataForLanguage[dataKey];
                    if (metadataForKey.inherited) {
                        this.keysToWatch.push({
                            lang: currentLanguage,
                            key: dataKey
                        });
                    }
                }
            }
        }
    },

    getLayoutEdit: function (showMode) {

        this.fieldConfig.datatype ="layout";
        this.fieldConfig.fieldtype = "panel";

        var wrapperConfig = {
            border: false,
            layout: "fit"
        };

        if(this.fieldConfig.width) {
            wrapperConfig.width = this.fieldConfig.width;
        }

        if(this.fieldConfig.region) {
            wrapperConfig.region = this.fieldConfig.region;
        }

        if(this.fieldConfig.title) {
            wrapperConfig.title = this.fieldConfig.title;
        }

        var nrOfLanguages = this.frontendLanguages.length;

        if (this.dropdownLayout) {
            //TODO choose default language
            var data = [];
            for (var i = 0; i < nrOfLanguages; i++) {
                var language = this.frontendLanguages[i];
                data.push([language, ts(pimcore.available_languages[language])]);
            }

            var store = new Ext.data.ArrayStore({
                    fields: ["key", "value"],
                    data: data
                }
            );

            var options = {
                triggerAction: "all",
                editable: true,
                selectOnFocus: true,
                queryMode: 'local',
                typeAhead: true,
                forceSelection: true,
                store: store,
                itemCls: "object_field",
                mode: "local",
                width: 300,
                padding: 10,
                displayField: "value",
                valueField: "key",
                value: this.frontendLanguages[0],
                listeners:  {
                    select:    function( combo, record, index ) {
                        var oldLanguage = this.currentLanguage;
                        var newLanguage = record.data.key;
                        if (oldLanguage == newLanguage) {
                            return;
                        }

                        this.availablePanels[oldLanguage].hide();
                        this.availablePanels[newLanguage].show();
                        this.currentLanguage = newLanguage;
                        this.component.doLayout();
                    }.bind(this)
                }
            };

            this.countrySelect = new Ext.form.ComboBox(options);

            wrapperConfig.items = []

            //TODO choose default language, maybe user-specific ?
            for (var i = nrOfLanguages - 1; i >= 0; i--) {
                this.currentLanguage = this.frontendLanguages[i];
                this.languageElements[this.currentLanguage] = [];

                var editable =  !showMode && (pimcore.currentuser.admin ||
                    this.fieldConfig.permissionEdit === undefined ||  this.fieldConfig.permissionEdit.length == 0 || in_array(this.currentLanguage, this.fieldConfig.permissionEdit));

                var items =  this.getRecursiveLayout(this.fieldConfig, !editable).items;

                var panelConf = {
                    height: "auto",
                    layout: "pimcoreform",
                    border: true,
                    padding: "10px",
                    title: pimcore.available_languages[this.frontendLanguages[i]],
                    items: items,
                    hidden: (i > 0)     //TODO default language
                };

                if(this.fieldConfig.height) {
                    panelConf.height = this.fieldConfig.height;
                    panelConf.autoHeight = false;
                    panelConf.autoScroll = true;
                } else {
                    panelConf.autoHeight = true;
                }

                if (this.fieldConfig.labelWidth) {
                    panelConf.labelWidth = this.fieldConfig.labelWidth;
                }

                this.tabPanel = new Ext.Panel(panelConf);

                this.availablePanels[this.currentLanguage] = this.tabPanel;
                wrapperConfig.items.push(this.tabPanel);

                wrapperConfig.tbar = [new Ext.Toolbar.TextItem({
                    text: t("language")
                }), this.countrySelect];
            }
        } else {
            var panelConf = {
                autoScroll: true,
                monitorResize: true,
                cls: "object_field",
                activeTab: 0,
                height: 10,
                items: [],
                deferredRender: true,
                forceLayout: true,
                hideMode: "offsets",
                enableTabScroll:true
            };

            if(this.fieldConfig.height) {
                panelConf.height = this.fieldConfig.height;
                panelConf.autoHeight = false;
            }

            // this is because the tabpanel has a strange behavior with automatic height, this corrects the problem
            panelConf.listeners = {
                afterrender: function () {
                    this.tabPanelAdjustIntervalCounter = 0;
                    this.tabPanelAdjustInterval = window.setInterval(function () {

                        this.tabPanelAdjustIntervalCounter++;
                        if(this.tabPanelAdjustIntervalCounter > 20) {
                            clearInterval(this.tabPanelAdjustInterval);
                        }

                        if(!this.fieldConfig.height && !this.fieldConfig.region) {
                            try {
                                var panelBodies = this.tabPanel.items.first().getEl().query(".x-panel-body");
                                var panelBody = Ext.get(panelBodies[0]);
                                panelBody.applyStyles("height: auto;");
                                var height = panelBody.getHeight();
                                // 100 is just a fixed value which seems to be ok(caused by title bar, tabs itself, ... )
                                this.component.setHeight(height+100);

                                //this.tabPanel.getEl().applyStyles("position:relative;");
                                this.component.doLayout();
                            } catch (e) {
                                console.log(e);
                            }
                        }
                    }.bind(this), 100);
                }.bind(this)
            };

            for (var i=0; i < nrOfLanguages; i++) {
                this.currentLanguage = this.frontendLanguages[i];
                this.languageElements[this.currentLanguage] = [];

                var editable =  (pimcore.currentuser.admin ||
                    this.fieldConfig.permissionEdit === undefined ||  this.fieldConfig.permissionEdit.length == 0 || in_array(this.currentLanguage, this.fieldConfig.permissionEdit));

                var item = {
                    xtype: "panel",
                    layout: "pimcoreform",
                    border:false,
                    autoScroll: true,
                    padding: "10px",
                    deferredRender: false,
                    hideMode: "offsets",
                    title: pimcore.available_languages[this.frontendLanguages[i]],
                    items: this.getRecursiveLayout(this.fieldConfig, !editable).items
                };

                if (this.fieldConfig.labelWidth) {
                    item.labelWidth = this.fieldConfig.labelWidth;
            }

                panelConf.items.push(item);
            }

            this.tabPanel = new Ext.TabPanel(panelConf);

            wrapperConfig.items = [this.tabPanel];
        }

        this.component = new Ext.Panel(wrapperConfig);
        this.component.doLayout();
        return this.component;
    },

    getLayoutShow: function () {

        this.component = this.getLayoutEdit(true);
        return this.component;
    },

    getDataForField: function (name) {
        try {
            if (this.data[this.currentLanguage]) {
                if (typeof this.data[this.currentLanguage][name] !== undefined){
                    return this.data[this.currentLanguage][name];
                }
            }
        } catch (e) {
            console.log(e);
        }
        return;
    },

    getMetaDataForField: function(name) {
        try {
            if (this.metaData[this.currentLanguage]) {
                if (this.metaData[this.currentLanguage][name]) {
                    return this.metaData[this.currentLanguage][name];
                } else if (typeof this.data[this.currentLanguage][name] !== undefined){
                    return null;
                }
            }
        } catch (e) {
            console.log(e);
        }
        return;

    },

    addToDataFields: function (field, name) {
        this.languageElements[this.currentLanguage].push(field);
    },

    addReferencedField: function (field) {
        this.referencedFields.push(field);
    },

    getValue: function () {

        var localizedData = {};
        var currentLanguage;

        for (var i=0; i < this.frontendLanguages.length; i++) {
            currentLanguage = this.frontendLanguages[i];
            localizedData[currentLanguage] = {};

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isDirty()) {
                    localizedData[currentLanguage][this.languageElements[currentLanguage][s].getName()]
                        = this.languageElements[currentLanguage][s].getValue();
                }
            }
        }

        // also add the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                localizedData = array_merge_recursive(localizedData, this.referencedFields[r].getValue());
            }
        }

        return localizedData;
    },

    getName: function () {
        return this.fieldConfig.name;
    },

    isDirty: function() {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                if(this.referencedFields[r].isDirty()) {
                    return true;
                }
            }
        }

        if(!this.isRendered()) {
            return false;
        }

        var currentLanguage;

        for (var i=0; i < this.frontendLanguages.length; i++) {

            currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isDirty()) {
                    return true;
                }
            }
        }

        return false;
    },

    isMandatory: function () {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                if(this.referencedFields[r].isMandatory()) {
                    return true;
                }
            }
        }

        var currentLanguage;

        for (var i=0; i < this.frontendLanguages; i++) {

            currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isMandatory()) {
                    return true;
                }
            }
        }

        return false;
    },

    isInvalidMandatory: function () {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                if(this.referencedFields[r].isInvalidMandatory()) {
                    return true;
                }
            }
        }

        var currentLanguage;
        var isInvalid = false;
        var invalidMandatoryFields = [];

        for (var i=0; i < this.frontendLanguages.length; i++) {

            currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isMandatory()) {
                    if(this.languageElements[currentLanguage][s].isInvalidMandatory()) {
                        invalidMandatoryFields.push(this.languageElements[currentLanguage][s].getTitle() + " - "
                            + currentLanguage.toUpperCase() + " ("
                            + this.languageElements[currentLanguage][s].getName() + ")");
                        isInvalid = true;
                    }
                }
            }
        }

        // return the error messages not bool, this is handled in object/edit.js
        if(isInvalid) {
            return invalidMandatoryFields;
        }

        return isInvalid;
    },

    dataIsNotInherited: function() {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                this.referencedFields[r].dataIsNotInherited();
            }
        }

        if (!this.inherited) {
            return true;
        }

        var foundUnmodifiedInheritedField = false;
        for (var i=0; i < this.frontendLanguages.length; i++) {

            var currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {

                if (this.metaData[currentLanguage]) {
                    var languageElement = this.languageElements[currentLanguage][s];
                    var key = languageElement.name;
                    if (this.metaData[currentLanguage][key]) {
                        if (this.metaData[currentLanguage][key].inherited) {
                            if(languageElement.isDirty()) {
                                this.metaData[currentLanguage][key].inherited = false;
                                languageElement.unmarkInherited();
                            } else {
                                foundUnmodifiedInheritedField = true;
                            }
                        }
                    }
                }
            }
        }

        if (!foundUnmodifiedInheritedField) {
            this.inherited = false;
        }
        return !this.inherited;
    },

    markInherited:function (metaData) {
        // nothing to do, only sub-elements can be marked
    }

});

pimcore.object.tags.localizedfields.addMethods(pimcore.object.helpers.edit);<commit_msg>PIMCORE-2542 - Switching between Objects causes wrong view<commit_after>/**
 * Pimcore
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.pimcore.org/license
 *
 * @copyright  Copyright (c) 2009-2014 pimcore GmbH (http://www.pimcore.org)
 * @license    http://www.pimcore.org/license     New BSD License
 */

pimcore.registerNS("pimcore.object.tags.localizedfields");
pimcore.object.tags.localizedfields = Class.create(pimcore.object.tags.abstract, {

    type: "localizedfields",

    frontendLanguages: null,

    initialize: function (data, fieldConfig) {

        this.data = {};
        this.metaData = {};
        this.inherited = false;
        this.languageElements = {};
        this.inheritedFields = {};
        this.referencedFields = [];
        this.availablePanels = [];
        this.dropdownLayout = false;

        if (pimcore.currentuser.admin || fieldConfig.permissionView === undefined) {
            this.frontendLanguages = pimcore.settings.websiteLanguages;
        } else {
            this.frontendLanguages = fieldConfig.permissionView;
        }

        var maxTabs = 15;
        if (typeof fieldConfig.maxTabs == "number") {
            maxTabs = fieldConfig.maxTabs;
        }

        if (this.frontendLanguages.length > maxTabs) {
            this.dropdownLayout = true;
        }

        if (data) {
            if (data.data) {
                this.data = data.data;
            }
            if (data.metaData) {
                this.metaData = data.metaData;
            }
            if (data.inherited) {
                this.inherited = data.inherited;
            }
        }
        this.fieldConfig = fieldConfig;

        this.keysToWatch = [];

        if (this.inherited) {
            for (var i=0; i < this.frontendLanguages.length; i++) {
                var currentLanguage = this.frontendLanguages[i];

                var metadataForLanguage = this.metaData[currentLanguage];
                var dataKeys = Object.keys(metadataForLanguage);

                for (var k = 0; k < dataKeys.length; k++) {
                    var dataKey = dataKeys[k];
                    var metadataForKey = metadataForLanguage[dataKey];
                    if (metadataForKey.inherited) {
                        this.keysToWatch.push({
                            lang: currentLanguage,
                            key: dataKey
                        });
                    }
                }
            }
        }
    },

    getLayoutEdit: function (showMode) {

        this.fieldConfig.datatype ="layout";
        this.fieldConfig.fieldtype = "panel";

        var wrapperConfig = {
            border: false,
            layout: "fit"
        };

        if(this.fieldConfig.width) {
            wrapperConfig.width = this.fieldConfig.width;
        }

        if(this.fieldConfig.region) {
            wrapperConfig.region = this.fieldConfig.region;
        }

        if(this.fieldConfig.title) {
            wrapperConfig.title = this.fieldConfig.title;
        }

        var nrOfLanguages = this.frontendLanguages.length;

        if (this.dropdownLayout) {
            //TODO choose default language
            var data = [];
            for (var i = 0; i < nrOfLanguages; i++) {
                var language = this.frontendLanguages[i];
                data.push([language, ts(pimcore.available_languages[language])]);
            }

            var store = new Ext.data.ArrayStore({
                    fields: ["key", "value"],
                    data: data
                }
            );

            var options = {
                triggerAction: "all",
                editable: true,
                selectOnFocus: true,
                queryMode: 'local',
                typeAhead: true,
                forceSelection: true,
                store: store,
                itemCls: "object_field",
                mode: "local",
                width: 300,
                padding: 10,
                displayField: "value",
                valueField: "key",
                value: this.frontendLanguages[0],
                listeners:  {
                    select:    function( combo, record, index ) {
                        var oldLanguage = this.currentLanguage;
                        var newLanguage = record.data.key;
                        if (oldLanguage == newLanguage) {
                            return;
                        }

                        this.availablePanels[oldLanguage].hide();
                        this.availablePanels[newLanguage].show();
                        this.currentLanguage = newLanguage;
                        this.component.doLayout();
                    }.bind(this)
                }
            };

            this.countrySelect = new Ext.form.ComboBox(options);

            wrapperConfig.items = []

            //TODO choose default language, maybe user-specific ?
            for (var i = nrOfLanguages - 1; i >= 0; i--) {
                this.currentLanguage = this.frontendLanguages[i];
                this.languageElements[this.currentLanguage] = [];

                var editable =  !showMode && (pimcore.currentuser.admin ||
                    this.fieldConfig.permissionEdit === undefined ||  this.fieldConfig.permissionEdit.length == 0 || in_array(this.currentLanguage, this.fieldConfig.permissionEdit));

                var items =  this.getRecursiveLayout(this.fieldConfig, !editable).items;

                var panelConf = {
                    height: "auto",
                    layout: "pimcoreform",
                    border: true,
                    padding: "10px",
                    title: pimcore.available_languages[this.frontendLanguages[i]],
                    items: items,
                    hidden: (i > 0)     //TODO default language
                };

                if(this.fieldConfig.height) {
                    panelConf.height = this.fieldConfig.height;
                    panelConf.autoHeight = false;
                    panelConf.autoScroll = true;
                } else {
                    panelConf.autoHeight = true;
                }

                if (this.fieldConfig.labelWidth) {
                    panelConf.labelWidth = this.fieldConfig.labelWidth;
                }

                this.tabPanel = new Ext.Panel(panelConf);

                this.availablePanels[this.currentLanguage] = this.tabPanel;
                wrapperConfig.items.push(this.tabPanel);

                wrapperConfig.tbar = [new Ext.Toolbar.TextItem({
                    text: t("language")
                }), this.countrySelect];
            }
        } else {
            var panelConf = {
                autoScroll: true,
                monitorResize: true,
                cls: "object_field",
                activeTab: 0,
                height: "auto",
                items: [],
                deferredRender: true,
                forceLayout: true,
                hideMode: "offsets",
                enableTabScroll:true
            };

            if(this.fieldConfig.height) {
                panelConf.height = this.fieldConfig.height;
                panelConf.autoHeight = false;
            }

            // this is because the tabpanel has a strange behavior with automatic height, this corrects the problem
            panelConf.listeners = {

                afterlayout: function () {
                    if (this.component.heightAlreadyFixed) {
                        return;
                    }

                    this.tabPanelAdjustIntervalCounter = 0;
                    this.tabPanelAdjustInterval = window.setInterval(function () {
                        if(!this.fieldConfig.height && !this.fieldConfig.region) {
                            this.tabPanelAdjustIntervalCounter++;
                            if(this.tabPanelAdjustIntervalCounter > 20) {
                                clearInterval(this.tabPanelAdjustInterval);
                            }

                            try {
                                var panelBodies = this.tabPanel.items.first().getEl().query(".x-panel-body");
                                var panelBody = Ext.get(panelBodies[0]);
                                panelBody.applyStyles("height: auto;");
                                var height = panelBody.getHeight();
                                if (height > 0) {
                                    // 100 is just a fixed value which seems to be ok(caused by title bar, tabs itself, ... )
                                    this.component.setHeight(height+100);
                                    clearInterval(this.tabPanelAdjustInterval);

                                    //this.tabPanel.getEl().applyStyles("position:relative;");
                                    this.component.doLayout();
                                    this.component.heightAlreadyFixed = true;

                                }

                            } catch (e) {
                                console.log(e);
                            }
                        }
                    }.bind(this), 100);
                }.bind(this)
            };

            for (var i=0; i < nrOfLanguages; i++) {
                this.currentLanguage = this.frontendLanguages[i];
                this.languageElements[this.currentLanguage] = [];

                var editable =  (pimcore.currentuser.admin ||
                    this.fieldConfig.permissionEdit === undefined ||  this.fieldConfig.permissionEdit.length == 0 || in_array(this.currentLanguage, this.fieldConfig.permissionEdit));

                var item = {
                    xtype: "panel",
                    layout: "pimcoreform",
                    border:false,
                    autoScroll: true,
                    padding: "10px",
                    deferredRender: false,
                    hideMode: "offsets",
                    title: pimcore.available_languages[this.frontendLanguages[i]],
                    items: this.getRecursiveLayout(this.fieldConfig, !editable).items
                };

                if (this.fieldConfig.labelWidth) {
                    item.labelWidth = this.fieldConfig.labelWidth;
            }

                panelConf.items.push(item);
            }

            this.tabPanel = new Ext.TabPanel(panelConf);

            wrapperConfig.items = [this.tabPanel];
        }

        this.component = new Ext.Panel(wrapperConfig);
        this.component.doLayout();
        return this.component;
    },

    getLayoutShow: function () {

        this.component = this.getLayoutEdit(true);
        return this.component;
    },

    getDataForField: function (name) {
        try {
            if (this.data[this.currentLanguage]) {
                if (typeof this.data[this.currentLanguage][name] !== undefined){
                    return this.data[this.currentLanguage][name];
                }
            }
        } catch (e) {
            console.log(e);
        }
        return;
    },

    getMetaDataForField: function(name) {
        try {
            if (this.metaData[this.currentLanguage]) {
                if (this.metaData[this.currentLanguage][name]) {
                    return this.metaData[this.currentLanguage][name];
                } else if (typeof this.data[this.currentLanguage][name] !== undefined){
                    return null;
                }
            }
        } catch (e) {
            console.log(e);
        }
        return;

    },

    addToDataFields: function (field, name) {
        this.languageElements[this.currentLanguage].push(field);
    },

    addReferencedField: function (field) {
        this.referencedFields.push(field);
    },

    getValue: function () {

        var localizedData = {};
        var currentLanguage;

        for (var i=0; i < this.frontendLanguages.length; i++) {
            currentLanguage = this.frontendLanguages[i];
            localizedData[currentLanguage] = {};

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isDirty()) {
                    localizedData[currentLanguage][this.languageElements[currentLanguage][s].getName()]
                        = this.languageElements[currentLanguage][s].getValue();
                }
            }
        }

        // also add the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                localizedData = array_merge_recursive(localizedData, this.referencedFields[r].getValue());
            }
        }

        return localizedData;
    },

    getName: function () {
        return this.fieldConfig.name;
    },

    isDirty: function() {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                if(this.referencedFields[r].isDirty()) {
                    return true;
                }
            }
        }

        if(!this.isRendered()) {
            return false;
        }

        var currentLanguage;

        for (var i=0; i < this.frontendLanguages.length; i++) {

            currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isDirty()) {
                    return true;
                }
            }
        }

        return false;
    },

    isMandatory: function () {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                if(this.referencedFields[r].isMandatory()) {
                    return true;
                }
            }
        }

        var currentLanguage;

        for (var i=0; i < this.frontendLanguages; i++) {

            currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isMandatory()) {
                    return true;
                }
            }
        }

        return false;
    },

    isInvalidMandatory: function () {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                if(this.referencedFields[r].isInvalidMandatory()) {
                    return true;
                }
            }
        }

        var currentLanguage;
        var isInvalid = false;
        var invalidMandatoryFields = [];

        for (var i=0; i < this.frontendLanguages.length; i++) {

            currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isMandatory()) {
                    if(this.languageElements[currentLanguage][s].isInvalidMandatory()) {
                        invalidMandatoryFields.push(this.languageElements[currentLanguage][s].getTitle() + " - "
                            + currentLanguage.toUpperCase() + " ("
                            + this.languageElements[currentLanguage][s].getName() + ")");
                        isInvalid = true;
                    }
                }
            }
        }

        // return the error messages not bool, this is handled in object/edit.js
        if(isInvalid) {
            return invalidMandatoryFields;
        }

        return isInvalid;
    },

    dataIsNotInherited: function() {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                this.referencedFields[r].dataIsNotInherited();
            }
        }

        if (!this.inherited) {
            return true;
        }

        var foundUnmodifiedInheritedField = false;
        for (var i=0; i < this.frontendLanguages.length; i++) {

            var currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {

                if (this.metaData[currentLanguage]) {
                    var languageElement = this.languageElements[currentLanguage][s];
                    var key = languageElement.name;
                    if (this.metaData[currentLanguage][key]) {
                        if (this.metaData[currentLanguage][key].inherited) {
                            if(languageElement.isDirty()) {
                                this.metaData[currentLanguage][key].inherited = false;
                                languageElement.unmarkInherited();
                            } else {
                                foundUnmodifiedInheritedField = true;
                            }
                        }
                    }
                }
            }
        }

        if (!foundUnmodifiedInheritedField) {
            this.inherited = false;
        }
        return !this.inherited;
    },

    markInherited:function (metaData) {
        // nothing to do, only sub-elements can be marked
    }

});

pimcore.object.tags.localizedfields.addMethods(pimcore.object.helpers.edit);<|endoftext|>