<commit_before>// Current application name and access id resolver
// - App name is used to resolve application that should be served to user in web app
// - Access Id is used for resolution of recors which should be propagated to user web app,
//   in close future it will be also used for validation of changes coming from a clients

'use strict';

var memoize                     = require('memoizee/plain')
  , ensureDatabase              = require('dbjs/valid-dbjs')
  , defineStringLine            = require('dbjs-ext/string/string-line')
  , defineUser                  = require('./base')
  , defineUserBusinessProcesses = require('./business-processes');

module.exports = memoize(function (db/* options */) {
	var User = ensureDatabase(db).User || defineUser(db, arguments[1])
	  , StringLine = defineStringLine(db);

	defineUserBusinessProcesses(User, arguments[1]);

	User.prototype.defineProperties({
		appAccessId: {
			type: StringLine,
			value: function (_observe) {
				var appId = this.__id__, role = this.currentRoleResolved, businessProcess, user;
				if (!role) return appId;
				appId += '.' + role;
				if (role === 'manager') {
					if (_observe(this.managerDataForms._progress) !== 1) {
						appId += '.registration';
						return appId;
					}
					user = this.currentlyManagedUser;
					if (!user) return appId;
					appId += '.' + user.__id__;
				}
				if ((role === 'user') || (role === 'manager')) {
					businessProcess = this.currentBusinessProcess;
					if (businessProcess) appId += '.' + businessProcess.__id__;
				}
				if (/^official[A-Z]/.test(role)) appId += (this.appAccessIdOfficialPostfix || '');
				return appId;
			}
		},
		appAccessIdOfficialPostfix: {
			type: StringLine
		},
		appName: {
			type: StringLine,
			value: function (_observe) {
				var role = this.currentRoleResolved, businessProcess;

				if (!role) return 'public';

				if ((role === 'user') || (role === 'manager')) {
					if (role === 'manager') {
						if (_observe(this.managerDataForms._progress) !== 1) return 'manager-registration';
						if (!this.currentlyManagedUser) return 'manager';
					}
					businessProcess = this.currentBusinessProcess;
					if (!businessProcess) {
						return this.appNameUser || 'public';
					}
					if (!_observe(businessProcess._isAtDraft)) return 'business-process-submitted';
					return this.appNameBusinessProcess;
				}

				if (/^official[A-Z]/.test(role)) return this.appNameOfficial;

				return role.replace(/([A-Z])/g, '-$1').toLowerCase();
			}
		},
		appNameBusinessProcess: {
			type: StringLine,
			value: function (_observe) {
				var businessProcess = this.currentBusinessProcess;

				if (!businessProcess) return 'public';

				// Replace with camelToHyphen() when it'll be possible
				return 'business-process' +
					this.currentBusinessProcess.constructor.__id__.slice('BusinessProcess'.length)
						.replace(/([A-Z])/g, '-$1').toLowerCase();
			}
		},
		appNameUser: {
			type: StringLine,
			value: 'user'
		},
		appNameOfficial: {
			type: StringLine,
			value: function () {
				var role = this.currentRoleResolved;
				if (!role || !/^official[A-Z]/.test(role)) return;
				// Replace with role.camelToHyphen() when it'll be possible
				return role.replace(/([A-Z])/g, '-$1').toLowerCase();
			}
		}
	});
	return User;
}, { normalizer: require('memoizee/normalizers/get-1')() });
<commit_msg>Issue #1582. Don't return public app name in appNameBusinessProcess<commit_after>// Current application name and access id resolver
// - App name is used to resolve application that should be served to user in web app
// - Access Id is used for resolution of recors which should be propagated to user web app,
//   in close future it will be also used for validation of changes coming from a clients

'use strict';

var memoize                     = require('memoizee/plain')
  , ensureDatabase              = require('dbjs/valid-dbjs')
  , defineStringLine            = require('dbjs-ext/string/string-line')
  , defineUser                  = require('./base')
  , defineUserBusinessProcesses = require('./business-processes');

module.exports = memoize(function (db/* options */) {
	var User = ensureDatabase(db).User || defineUser(db, arguments[1])
	  , StringLine = defineStringLine(db);

	defineUserBusinessProcesses(User, arguments[1]);

	User.prototype.defineProperties({
		appAccessId: {
			type: StringLine,
			value: function (_observe) {
				var appId = this.__id__, role = this.currentRoleResolved, businessProcess, user;
				if (!role) return appId;
				appId += '.' + role;
				if (role === 'manager') {
					if (_observe(this.managerDataForms._progress) !== 1) {
						appId += '.registration';
						return appId;
					}
					user = this.currentlyManagedUser;
					if (!user) return appId;
					appId += '.' + user.__id__;
				}
				if ((role === 'user') || (role === 'manager')) {
					businessProcess = this.currentBusinessProcess;
					if (businessProcess) appId += '.' + businessProcess.__id__;
				}
				if (/^official[A-Z]/.test(role)) appId += (this.appAccessIdOfficialPostfix || '');
				return appId;
			}
		},
		appAccessIdOfficialPostfix: {
			type: StringLine
		},
		appName: {
			type: StringLine,
			value: function (_observe) {
				var role = this.currentRoleResolved, businessProcess;

				if (!role) return 'public';

				if ((role === 'user') || (role === 'manager')) {
					if (role === 'manager') {
						if (_observe(this.managerDataForms._progress) !== 1) return 'manager-registration';
						if (!this.currentlyManagedUser) return 'manager';
					}
					businessProcess = this.currentBusinessProcess;
					if (!businessProcess) {
						return this.appNameUser || 'public';
					}
					if (!_observe(businessProcess._isAtDraft)) return 'business-process-submitted';
					return this.appNameBusinessProcess;
				}

				if (/^official[A-Z]/.test(role)) return this.appNameOfficial;

				return role.replace(/([A-Z])/g, '-$1').toLowerCase();
			}
		},
		appNameBusinessProcess: {
			type: StringLine,
			value: function (_observe) {
				var businessProcess = this.currentBusinessProcess;

				if (!businessProcess) return;

				// Replace with camelToHyphen() when it'll be possible
				return 'business-process' +
					this.currentBusinessProcess.constructor.__id__.slice('BusinessProcess'.length)
						.replace(/([A-Z])/g, '-$1').toLowerCase();
			}
		},
		appNameUser: {
			type: StringLine,
			value: 'user'
		},
		appNameOfficial: {
			type: StringLine,
			value: function () {
				var role = this.currentRoleResolved;
				if (!role || !/^official[A-Z]/.test(role)) return;
				// Replace with role.camelToHyphen() when it'll be possible
				return role.replace(/([A-Z])/g, '-$1').toLowerCase();
			}
		}
	});
	return User;
}, { normalizer: require('memoizee/normalizers/get-1')() });
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Google Inc. All Rights Reserved.
 * 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 Util = require('./util.js');
var WakeLock = require('./wakelock.js');

// Start at a higher number to reduce chance of conflict.
var nextDisplayId = 1000;
var hasShowDeprecationWarning = false;

var defaultLeftBounds = [0, 0, 0.5, 1];
var defaultRightBounds = [0.5, 0, 0.5, 1];

/**
 * The base class for all VR displays.
 */
function VRDisplay() {
  this.isPolyfilled = true;
  this.displayId = nextDisplayId++;
  this.displayName = 'webvr-polyfill displayName';

  this.isConnected = true;
  this.isPresenting = false;
  this.capabilities = {
    hasPosition: false,
    hasOrientation: false,
    hasExternalDisplay: false,
    canPresent: false,
    maxLayers: 1
  };
  this.stageParameters = null;

  // "Private" members.
  this.waitingForPresent_ = false;
  this.layer_ = null;

  this.fullscreenElement_ = null;
  this.fullscreenWrapper_ = null;
  this.fullscreenElementCachedStyle_ = null;

  this.fullscreenEventTarget_ = null;
  this.fullscreenChangeHandler_ = null;
  this.fullscreenErrorHandler_ = null;

  this.wakelock_ = new WakeLock();
}

VRDisplay.prototype.getPose = function() {
  // TODO: Technically this should retain it's value for the duration of a frame
  // but I doubt that's practical to do in javascript.
  return this.getImmediatePose();
};

VRDisplay.prototype.requestAnimationFrame = function(callback) {
  return window.requestAnimationFrame(callback);
};

VRDisplay.prototype.cancelAnimationFrame = function(id) {
  return window.cancelAnimationFrame(id);
};

VRDisplay.prototype.wrapForFullscreen = function(element) {
  // Don't wrap in iOS.
  if (Util.isIOS()) {
    return element;
  }
  if (!this.fullscreenWrapper_) {
    this.fullscreenWrapper_ = document.createElement('div');
    var cssProperties = [
      'height: ' + Math.min(screen.height, screen.width) + 'px !important',
      'top: 0 !important',
      'left: 0 !important',
      'right: 0 !important',
      'border: 0',
      'margin: 0',
      'padding: 0',
      'z-index: 999999 !important',
      'position: fixed',
    ];
    this.fullscreenWrapper_.setAttribute('style', cssProperties.join('; ') + ';');
    this.fullscreenWrapper_.classList.add('webvr-polyfill-fullscreen-wrapper');
  }

  if (this.fullscreenElement_ == element) {
    return this.fullscreenWrapper_;
  }

  // Remove any previously applied wrappers
  this.removeFullscreenWrapper();

  this.fullscreenElement_ = element;
  var parent = this.fullscreenElement_.parentElement;
  parent.insertBefore(this.fullscreenWrapper_, this.fullscreenElement_);
  parent.removeChild(this.fullscreenElement_);
  this.fullscreenWrapper_.insertBefore(this.fullscreenElement_, this.fullscreenWrapper_.firstChild);
  this.fullscreenElementCachedStyle_ = this.fullscreenElement_.getAttribute('style');

  var self = this;
  function applyFullscreenElementStyle() {
    if (!self.fullscreenElement_) {
      return;
    }

    var cssProperties = [
      'position: absolute',
      'top: 0',
      'left: 0',
      'width: ' + Math.max(screen.width, screen.height) + 'px',
      'height: ' + Math.min(screen.height, screen.width) + 'px',
      'border: 0',
      'margin: 0',
      'padding: 0',
    ];
    self.fullscreenElement_.setAttribute('style', cssProperties.join('; ') + ';');
  }

  applyFullscreenElementStyle();

  return this.fullscreenWrapper_;
};

VRDisplay.prototype.removeFullscreenWrapper = function() {
  if (!this.fullscreenElement_) {
    return;
  }

  var element = this.fullscreenElement_;
  if (this.fullscreenElementCachedStyle_) {
    element.setAttribute('style', this.fullscreenElementCachedStyle_);
  } else {
    element.removeAttribute('style');
  }
  this.fullscreenElement_ = null;
  this.fullscreenElementCachedStyle_ = null;

  var parent = this.fullscreenWrapper_.parentElement;
  this.fullscreenWrapper_.removeChild(element);
  parent.insertBefore(element, this.fullscreenWrapper_);
  parent.removeChild(this.fullscreenWrapper_);

  return element;
};

VRDisplay.prototype.requestPresent = function(layers) {
  var wasPresenting = this.isPresenting;
  var self = this;

  if (!(layers instanceof Array)) {
    if (!hasShowDeprecationWarning) {
      console.warn("Using a deprecated form of requestPresent. Should pass in an array of VRLayers.");
      hasShowDeprecationWarning = true;
    }
    layers = [layers];
  }

  return new Promise(function(resolve, reject) {
    if (!self.capabilities.canPresent) {
      reject(new Error('VRDisplay is not capable of presenting.'));
      return;
    }

    if (layers.length == 0 || layers.length > self.capabilities.maxLayers) {
      reject(new Error('Invalid number of layers.'));
      return;
    }

    var incomingLayer = layers[0];
    if (!incomingLayer.source) {
      /*
      todo: figure out the correct behavior if the source is not provided.
      see https://github.com/w3c/webvr/issues/58
      */
      resolve();
      return;
    }

    var leftBounds = incomingLayer.leftBounds || defaultLeftBounds;
    var rightBounds = incomingLayer.rightBounds || defaultRightBounds;
    if (wasPresenting) {
      // Already presenting, just changing configuration
      var changed = false;
      var layer = self.layer_;
      if (layer.source !== incomingLayer.source) {
        layer.source = incomingLayer.source;
        changed = true;
      }

      for (var i = 0; i < 4; i++) {
        if (layer.leftBounds[i] !== leftBounds[i]) {
          layer.leftBounds[i] = leftBounds[i];
          changed = true;
        }
        if (layer.rightBounds[i] !== rightBounds[i]) {
          layer.rightBounds[i] = rightBounds[i];
          changed = true;
        }
      }

      if (changed) {
        self.fireVRDisplayPresentChange_();
      }
      resolve();
      return;
    }

    // Was not already presenting.
    self.layer_ = {
      predistorted: incomingLayer.predistorted,
      source: incomingLayer.source,
      leftBounds: leftBounds.slice(0),
      rightBounds: rightBounds.slice(0)
    };

    self.waitingForPresent_ = false;
    if (self.layer_ && self.layer_.source) {
      var fullscreenElement = self.wrapForFullscreen(self.layer_.source);

      function onFullscreenChange() {
        var actualFullscreenElement = Util.getFullscreenElement();

        self.isPresenting = (fullscreenElement === actualFullscreenElement);
        if (self.isPresenting) {
          if (screen.orientation && screen.orientation.lock) {
            screen.orientation.lock('landscape-primary').catch(function(error){
                    console.error('screen.orientation.lock() failed due to', error.message)
            });
          }
          self.waitingForPresent_ = false;
          self.beginPresent_();
          resolve();
        } else {
          if (screen.orientation && screen.orientation.unlock) {
            screen.orientation.unlock();
          }
          self.removeFullscreenWrapper();
          self.wakelock_.release();
          self.endPresent_();
          self.removeFullscreenListeners_();
        }
        self.fireVRDisplayPresentChange_();
      }
      function onFullscreenError() {
        if (!self.waitingForPresent_) {
          return;
        }

        self.removeFullscreenWrapper();
        self.removeFullscreenListeners_();

        self.wakelock_.release();
        self.waitingForPresent_ = false;
        self.isPresenting = false;

        reject(new Error('Unable to present.'));
      }

      self.addFullscreenListeners_(fullscreenElement,
          onFullscreenChange, onFullscreenError);

      if (Util.requestFullscreen(fullscreenElement)) {
        self.wakelock_.request();
        self.waitingForPresent_ = true;
      } else if (Util.isIOS()) {
        // *sigh* Just fake it.
        self.wakelock_.request();
        self.isPresenting = true;
        self.beginPresent_();
        self.fireVRDisplayPresentChange_();
        resolve();
      }
    }

    if (!self.waitingForPresent_ && !Util.isIOS()) {
      Util.exitFullscreen();
      reject(new Error('Unable to present.'));
    }
  });
};

VRDisplay.prototype.exitPresent = function() {
  var wasPresenting = this.isPresenting;
  var self = this;
  this.isPresenting = false;
  this.layer_ = null;
  this.wakelock_.release();

  return new Promise(function(resolve, reject) {
    if (wasPresenting) {
      if (!Util.exitFullscreen() && Util.isIOS()) {
        self.endPresent_();
        self.fireVRDisplayPresentChange_();
      }

      resolve();
    } else {
      reject(new Error('Was not presenting to VRDisplay.'));
    }
  });
};

VRDisplay.prototype.getLayers = function() {
  if (this.layer_) {
    return [this.layer_];
  }
  return [];
};

VRDisplay.prototype.fireVRDisplayPresentChange_ = function() {
  var event = new CustomEvent('vrdisplaypresentchange', {detail: {vrdisplay: this}});
  window.dispatchEvent(event);
};

VRDisplay.prototype.addFullscreenListeners_ = function(element, changeHandler, errorHandler) {
  this.removeFullscreenListeners_();

  this.fullscreenEventTarget_ = element;
  this.fullscreenChangeHandler_ = changeHandler;
  this.fullscreenErrorHandler_ = errorHandler;

  if (changeHandler) {
    if (document.fullscreenEnabled) element.addEventListener('fullscreenchange', changeHandler, false);
	  else if (document.webkitFullscreenEnabled) element.addEventListener('webkitfullscreenchange', changeHandler, false);
	  else if (document.mozFullscreenEnabled) document.addEventListener('mozfullscreenchange', changeHandler, false);
	  else if (document.msFullscreenEnabled) element.addEventListener('msfullscreenchange', changeHandler, false);
  }

  if (errorHandler) {
    if (document.fullscreenEnabled) element.addEventListener('fullscreenerror', errorHandler, false);
	  else if (document.webkitFullscreenEnabled) element.addEventListener('webkitfullscreenerror', errorHandler, false);
	  else if (document.mozFullscreenEnabled) document.addEventListener('mozfullscreenerror', errorHandler, false);
	  else if (document.msFullscreenEnabled) element.addEventListener('msfullscreenerror', errorHandler, false);
  }
};

VRDisplay.prototype.removeFullscreenListeners_ = function() {
  if (!this.fullscreenEventTarget_)
    return;

  var element = this.fullscreenEventTarget_;

  if (this.fullscreenChangeHandler_) {
    var changeHandler = this.fullscreenChangeHandler_;
    element.removeEventListener('fullscreenchange', changeHandler, false);
    element.removeEventListener('webkitfullscreenchange', changeHandler, false);
    document.removeEventListener('mozfullscreenchange', changeHandler, false);
    element.removeEventListener('msfullscreenchange', changeHandler, false);
  }

  if (this.fullscreenErrorHandler_) {
    var errorHandler = this.fullscreenErrorHandler_;
    element.removeEventListener('fullscreenerror', errorHandler, false);
    element.removeEventListener('webkitfullscreenerror', errorHandler, false);
    document.removeEventListener('mozfullscreenerror', errorHandler, false);
    element.removeEventListener('msfullscreenerror', errorHandler, false);
  }

  this.fullscreenEventTarget_ = null;
  this.fullscreenChangeHandler_ = null;
  this.fullscreenErrorHandler_ = null;
};

VRDisplay.prototype.beginPresent_ = function() {
  // Override to add custom behavior when presentation begins.
};

VRDisplay.prototype.endPresent_ = function() {
  // Override to add custom behavior when presentation ends.
};

VRDisplay.prototype.submitFrame = function(pose) {
  // Override to add custom behavior for frame submission.
};

VRDisplay.prototype.getEyeParameters = function(whichEye) {
  // Override to return accurate eye parameters if canPresent is true.
  return null;
};

/*
 * Deprecated classes
 */

/**
 * The base class for all VR devices. (Deprecated)
 */
function VRDevice() {
  this.isPolyfilled = true;
  this.hardwareUnitId = 'webvr-polyfill hardwareUnitId';
  this.deviceId = 'webvr-polyfill deviceId';
  this.deviceName = 'webvr-polyfill deviceName';
}

/**
 * The base class for all VR HMD devices. (Deprecated)
 */
function HMDVRDevice() {
}
HMDVRDevice.prototype = new VRDevice();

/**
 * The base class for all VR position sensor devices. (Deprecated)
 */
function PositionSensorVRDevice() {
}
PositionSensorVRDevice.prototype = new VRDevice();

module.exports.VRDisplay = VRDisplay;
module.exports.VRDevice = VRDevice;
module.exports.HMDVRDevice = HMDVRDevice;
module.exports.PositionSensorVRDevice = PositionSensorVRDevice;
<commit_msg>Adjusted coding style of commit 71211f2c5a3bba4638dd639a6ebac100464734b2<commit_after>/*
 * Copyright 2015 Google Inc. All Rights Reserved.
 * 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 Util = require('./util.js');
var WakeLock = require('./wakelock.js');

// Start at a higher number to reduce chance of conflict.
var nextDisplayId = 1000;
var hasShowDeprecationWarning = false;

var defaultLeftBounds = [0, 0, 0.5, 1];
var defaultRightBounds = [0.5, 0, 0.5, 1];

/**
 * The base class for all VR displays.
 */
function VRDisplay() {
  this.isPolyfilled = true;
  this.displayId = nextDisplayId++;
  this.displayName = 'webvr-polyfill displayName';

  this.isConnected = true;
  this.isPresenting = false;
  this.capabilities = {
    hasPosition: false,
    hasOrientation: false,
    hasExternalDisplay: false,
    canPresent: false,
    maxLayers: 1
  };
  this.stageParameters = null;

  // "Private" members.
  this.waitingForPresent_ = false;
  this.layer_ = null;

  this.fullscreenElement_ = null;
  this.fullscreenWrapper_ = null;
  this.fullscreenElementCachedStyle_ = null;

  this.fullscreenEventTarget_ = null;
  this.fullscreenChangeHandler_ = null;
  this.fullscreenErrorHandler_ = null;

  this.wakelock_ = new WakeLock();
}

VRDisplay.prototype.getPose = function() {
  // TODO: Technically this should retain it's value for the duration of a frame
  // but I doubt that's practical to do in javascript.
  return this.getImmediatePose();
};

VRDisplay.prototype.requestAnimationFrame = function(callback) {
  return window.requestAnimationFrame(callback);
};

VRDisplay.prototype.cancelAnimationFrame = function(id) {
  return window.cancelAnimationFrame(id);
};

VRDisplay.prototype.wrapForFullscreen = function(element) {
  // Don't wrap in iOS.
  if (Util.isIOS()) {
    return element;
  }
  if (!this.fullscreenWrapper_) {
    this.fullscreenWrapper_ = document.createElement('div');
    var cssProperties = [
      'height: ' + Math.min(screen.height, screen.width) + 'px !important',
      'top: 0 !important',
      'left: 0 !important',
      'right: 0 !important',
      'border: 0',
      'margin: 0',
      'padding: 0',
      'z-index: 999999 !important',
      'position: fixed',
    ];
    this.fullscreenWrapper_.setAttribute('style', cssProperties.join('; ') + ';');
    this.fullscreenWrapper_.classList.add('webvr-polyfill-fullscreen-wrapper');
  }

  if (this.fullscreenElement_ == element) {
    return this.fullscreenWrapper_;
  }

  // Remove any previously applied wrappers
  this.removeFullscreenWrapper();

  this.fullscreenElement_ = element;
  var parent = this.fullscreenElement_.parentElement;
  parent.insertBefore(this.fullscreenWrapper_, this.fullscreenElement_);
  parent.removeChild(this.fullscreenElement_);
  this.fullscreenWrapper_.insertBefore(this.fullscreenElement_, this.fullscreenWrapper_.firstChild);
  this.fullscreenElementCachedStyle_ = this.fullscreenElement_.getAttribute('style');

  var self = this;
  function applyFullscreenElementStyle() {
    if (!self.fullscreenElement_) {
      return;
    }

    var cssProperties = [
      'position: absolute',
      'top: 0',
      'left: 0',
      'width: ' + Math.max(screen.width, screen.height) + 'px',
      'height: ' + Math.min(screen.height, screen.width) + 'px',
      'border: 0',
      'margin: 0',
      'padding: 0',
    ];
    self.fullscreenElement_.setAttribute('style', cssProperties.join('; ') + ';');
  }

  applyFullscreenElementStyle();

  return this.fullscreenWrapper_;
};

VRDisplay.prototype.removeFullscreenWrapper = function() {
  if (!this.fullscreenElement_) {
    return;
  }

  var element = this.fullscreenElement_;
  if (this.fullscreenElementCachedStyle_) {
    element.setAttribute('style', this.fullscreenElementCachedStyle_);
  } else {
    element.removeAttribute('style');
  }
  this.fullscreenElement_ = null;
  this.fullscreenElementCachedStyle_ = null;

  var parent = this.fullscreenWrapper_.parentElement;
  this.fullscreenWrapper_.removeChild(element);
  parent.insertBefore(element, this.fullscreenWrapper_);
  parent.removeChild(this.fullscreenWrapper_);

  return element;
};

VRDisplay.prototype.requestPresent = function(layers) {
  var wasPresenting = this.isPresenting;
  var self = this;

  if (!(layers instanceof Array)) {
    if (!hasShowDeprecationWarning) {
      console.warn("Using a deprecated form of requestPresent. Should pass in an array of VRLayers.");
      hasShowDeprecationWarning = true;
    }
    layers = [layers];
  }

  return new Promise(function(resolve, reject) {
    if (!self.capabilities.canPresent) {
      reject(new Error('VRDisplay is not capable of presenting.'));
      return;
    }

    if (layers.length == 0 || layers.length > self.capabilities.maxLayers) {
      reject(new Error('Invalid number of layers.'));
      return;
    }

    var incomingLayer = layers[0];
    if (!incomingLayer.source) {
      /*
      todo: figure out the correct behavior if the source is not provided.
      see https://github.com/w3c/webvr/issues/58
      */
      resolve();
      return;
    }

    var leftBounds = incomingLayer.leftBounds || defaultLeftBounds;
    var rightBounds = incomingLayer.rightBounds || defaultRightBounds;
    if (wasPresenting) {
      // Already presenting, just changing configuration
      var changed = false;
      var layer = self.layer_;
      if (layer.source !== incomingLayer.source) {
        layer.source = incomingLayer.source;
        changed = true;
      }

      for (var i = 0; i < 4; i++) {
        if (layer.leftBounds[i] !== leftBounds[i]) {
          layer.leftBounds[i] = leftBounds[i];
          changed = true;
        }
        if (layer.rightBounds[i] !== rightBounds[i]) {
          layer.rightBounds[i] = rightBounds[i];
          changed = true;
        }
      }

      if (changed) {
        self.fireVRDisplayPresentChange_();
      }
      resolve();
      return;
    }

    // Was not already presenting.
    self.layer_ = {
      predistorted: incomingLayer.predistorted,
      source: incomingLayer.source,
      leftBounds: leftBounds.slice(0),
      rightBounds: rightBounds.slice(0)
    };

    self.waitingForPresent_ = false;
    if (self.layer_ && self.layer_.source) {
      var fullscreenElement = self.wrapForFullscreen(self.layer_.source);

      function onFullscreenChange() {
        var actualFullscreenElement = Util.getFullscreenElement();

        self.isPresenting = (fullscreenElement === actualFullscreenElement);
        if (self.isPresenting) {
          if (screen.orientation && screen.orientation.lock) {
            screen.orientation.lock('landscape-primary').catch(function(error){
                    console.error('screen.orientation.lock() failed due to', error.message)
            });
          }
          self.waitingForPresent_ = false;
          self.beginPresent_();
          resolve();
        } else {
          if (screen.orientation && screen.orientation.unlock) {
            screen.orientation.unlock();
          }
          self.removeFullscreenWrapper();
          self.wakelock_.release();
          self.endPresent_();
          self.removeFullscreenListeners_();
        }
        self.fireVRDisplayPresentChange_();
      }
      function onFullscreenError() {
        if (!self.waitingForPresent_) {
          return;
        }

        self.removeFullscreenWrapper();
        self.removeFullscreenListeners_();

        self.wakelock_.release();
        self.waitingForPresent_ = false;
        self.isPresenting = false;

        reject(new Error('Unable to present.'));
      }

      self.addFullscreenListeners_(fullscreenElement,
          onFullscreenChange, onFullscreenError);

      if (Util.requestFullscreen(fullscreenElement)) {
        self.wakelock_.request();
        self.waitingForPresent_ = true;
      } else if (Util.isIOS()) {
        // *sigh* Just fake it.
        self.wakelock_.request();
        self.isPresenting = true;
        self.beginPresent_();
        self.fireVRDisplayPresentChange_();
        resolve();
      }
    }

    if (!self.waitingForPresent_ && !Util.isIOS()) {
      Util.exitFullscreen();
      reject(new Error('Unable to present.'));
    }
  });
};

VRDisplay.prototype.exitPresent = function() {
  var wasPresenting = this.isPresenting;
  var self = this;
  this.isPresenting = false;
  this.layer_ = null;
  this.wakelock_.release();

  return new Promise(function(resolve, reject) {
    if (wasPresenting) {
      if (!Util.exitFullscreen() && Util.isIOS()) {
        self.endPresent_();
        self.fireVRDisplayPresentChange_();
      }

      resolve();
    } else {
      reject(new Error('Was not presenting to VRDisplay.'));
    }
  });
};

VRDisplay.prototype.getLayers = function() {
  if (this.layer_) {
    return [this.layer_];
  }
  return [];
};

VRDisplay.prototype.fireVRDisplayPresentChange_ = function() {
  var event = new CustomEvent('vrdisplaypresentchange', {detail: {vrdisplay: this}});
  window.dispatchEvent(event);
};

VRDisplay.prototype.addFullscreenListeners_ = function(element, changeHandler, errorHandler) {
  this.removeFullscreenListeners_();

  this.fullscreenEventTarget_ = element;
  this.fullscreenChangeHandler_ = changeHandler;
  this.fullscreenErrorHandler_ = errorHandler;

  if (changeHandler) {
    if (document.fullscreenEnabled) {
      element.addEventListener('fullscreenchange', changeHandler, false);
    } else if (document.webkitFullscreenEnabled) {
      element.addEventListener('webkitfullscreenchange', changeHandler, false);
    } else if (document.mozFullScreenEnabled) {
      document.addEventListener('mozfullscreenchange', changeHandler, false);
    } else if (document.msFullscreenEnabled) {
      element.addEventListener('msfullscreenchange', changeHandler, false);
    }
  }

  if (errorHandler) {
    if (document.fullscreenEnabled) {
      element.addEventListener('fullscreenerror', errorHandler, false);
    } else if (document.webkitFullscreenEnabled) {
      element.addEventListener('webkitfullscreenerror', errorHandler, false);
    } else if (document.mozFullScreenEnabled) {
      document.addEventListener('mozfullscreenerror', errorHandler, false);
    } else if (document.msFullscreenEnabled) {
      element.addEventListener('msfullscreenerror', errorHandler, false);
    }
  }
};

VRDisplay.prototype.removeFullscreenListeners_ = function() {
  if (!this.fullscreenEventTarget_)
    return;

  var element = this.fullscreenEventTarget_;

  if (this.fullscreenChangeHandler_) {
    var changeHandler = this.fullscreenChangeHandler_;
    element.removeEventListener('fullscreenchange', changeHandler, false);
    element.removeEventListener('webkitfullscreenchange', changeHandler, false);
    document.removeEventListener('mozfullscreenchange', changeHandler, false);
    element.removeEventListener('msfullscreenchange', changeHandler, false);
  }

  if (this.fullscreenErrorHandler_) {
    var errorHandler = this.fullscreenErrorHandler_;
    element.removeEventListener('fullscreenerror', errorHandler, false);
    element.removeEventListener('webkitfullscreenerror', errorHandler, false);
    document.removeEventListener('mozfullscreenerror', errorHandler, false);
    element.removeEventListener('msfullscreenerror', errorHandler, false);
  }

  this.fullscreenEventTarget_ = null;
  this.fullscreenChangeHandler_ = null;
  this.fullscreenErrorHandler_ = null;
};

VRDisplay.prototype.beginPresent_ = function() {
  // Override to add custom behavior when presentation begins.
};

VRDisplay.prototype.endPresent_ = function() {
  // Override to add custom behavior when presentation ends.
};

VRDisplay.prototype.submitFrame = function(pose) {
  // Override to add custom behavior for frame submission.
};

VRDisplay.prototype.getEyeParameters = function(whichEye) {
  // Override to return accurate eye parameters if canPresent is true.
  return null;
};

/*
 * Deprecated classes
 */

/**
 * The base class for all VR devices. (Deprecated)
 */
function VRDevice() {
  this.isPolyfilled = true;
  this.hardwareUnitId = 'webvr-polyfill hardwareUnitId';
  this.deviceId = 'webvr-polyfill deviceId';
  this.deviceName = 'webvr-polyfill deviceName';
}

/**
 * The base class for all VR HMD devices. (Deprecated)
 */
function HMDVRDevice() {
}
HMDVRDevice.prototype = new VRDevice();

/**
 * The base class for all VR position sensor devices. (Deprecated)
 */
function PositionSensorVRDevice() {
}
PositionSensorVRDevice.prototype = new VRDevice();

module.exports.VRDisplay = VRDisplay;
module.exports.VRDevice = VRDevice;
module.exports.HMDVRDevice = HMDVRDevice;
module.exports.PositionSensorVRDevice = PositionSensorVRDevice;
<|endoftext|>


<commit_before>/*
 * Copyright 2006 Matthew Eernisse (mde@fleegix.org)
 *
 * 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.
 *
*/
if (typeof fleegix == 'undefined') { var fleegix = {}; }

fleegix.extend = function (/* Super-class constructor function */ superClass,
  /* Sub-class constructor function */ subClass) {
  return function () {
    superClass.apply(this, arguments);
    superClass.prototype.constructor.apply(this, arguments);
    subClass.apply(this, arguments);
  };
};

fleegix.mixin = function (/* Target obj */ target,
  /* Obj of props or constructor */ mixin) {
  // Create an instance if we get a constructor
  var m;
  if (typeof mixin == 'function') {
    m = new mixin();
  }
  else {
    m = mixin;
  }
  var baseObj = {};
  for (var p in m) {
    // Don't copy anything from Object.prototype
		if (typeof baseObj[p] == 'undefined' || baseObjj[p] != m[p]) {
      target[p] = m[p];
    }
  }
  return target;
};

<commit_msg>Added superClass and subClass refs to objects extended with fleegix.extend.<commit_after>/*
 * Copyright 2006 Matthew Eernisse (mde@fleegix.org)
 *
 * 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.
 *
*/
if (typeof fleegix == 'undefined') { var fleegix = {}; }

fleegix.extend = function (/* Super-class constructor function */ superClass,
  /* Sub-class constructor function */ subClass) {
  return function () {
    superClass.apply(this, arguments);
    superClass.prototype.constructor.apply(this, arguments);
    subClass.apply(this, arguments);
    this.superClass = superClass;
    this.subClass = subClass
  };
};

fleegix.mixin = function (/* Target obj */ target,
  /* Obj of props or constructor */ mixin) {
  // Create an instance if we get a constructor
  var m;
  if (typeof mixin == 'function') {
    m = new mixin();
  }
  else {
    m = mixin;
  }
  var baseObj = {};
  for (var p in m) {
    // Don't copy anything from Object.prototype
		if (typeof baseObj[p] == 'undefined' || baseObjj[p] != m[p]) {
      target[p] = m[p];
    }
  }
  return target;
};

<|endoftext|>


<commit_before>/*!
 * Copyright (c) 2012 Ben Olson (https://github.com/bseth99/basejs)
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Dependancies: None
 *
 */

(function (undefined) {

   var isArray = function( v ) {
      return (v && Object.prototype.toString.call( v ) === '[object Array]');
   }

   var isObject = function( v ) {
      return (v && typeof v == 'object');
   }

   var isFunction = function( v ) {
      return (v && typeof v == 'function');
   }

   /**
   * Deep copy a source variable to a target variable.
   *
   * @param target { Any }
   * @param source ( Any }
   *
   * Any enumerable type will create a copy of source into target
   * if the intrinsic value in target is not already defined.
   * Arrays and Objects will recursively attempt to copy items from
   * source to target to fill in any missing items.
   *
   */

   var merge = function(target, source) {

      if ( typeof(source) == 'undefined' )
         return target;

      if ( isObject(source) ) {

         target = target || (isArray(source) ? [] : {});

         for ( var p in source ) {

            if ( target[p] && source[p] === target[p] )
               continue;

            target[p] = merge( target[p], source[p] );
         }

      } else {

         if ( source instanceof Date )
            target = new Date(source);
         else
            target = source;

      }

      return target;
   }

   /**
   * Look for collisions and create wrappers to setup "super" chain
   * Enables chaining method automatically or manually via _super()
   *
   * @param target { Object } receiving object.
   *        Everything in source will be copied
   *        to the target object.  Collisions in function names will be wrapped
   *        such that the function in target will be available via the _super method
   *        while the source method is executing.  If auto is true, the target method
   *        will be executed after the source method is complete.  The return value of
   *        source will be used unless its undefined in which case the return from target
   *        will be used.
   *
   * @param source { Object } properties to merge into target
   *
   * @param options { Object } how to handle method and/or property name collisions
   *        Two hash values are allowed:
   *           {
   *              functions:  { Boolean | Object } function name collisions
   *              properties: { Boolean | Object } property name collisions
   *           }
   *
   *        Both options default to true.
   *
   *        For functions, the super chain will be called automatically.
   *        For properties, Arrays and Object hashes will be merged.  The source will override the
   *        target when there is an overlap.
   *
   *        Both options also takes a Hash of keys that can indicate (true/false) if they should
   *        be auto chained / merged
   *
   *        {
   *           functions: { init: true, foo: false, bar: true },
   *           properties: false  -- never merge - just overwrite with source
   *        }
   */

   var chain = function(target, source, options) {

      var options = options || {};

      options = {
            functions: typeof(options.functions) == 'undefined' ? true : options.functions,
            properties: typeof(options.properties) == 'undefined' ? true : options.properties
         };

      for ( var p in source ) {

         // Don't merge things not actually in source (in its prototype chain)
         if ( target[p] && source.hasOwnProperty(p) ) {

            // There is a collision - wrap up the methods in a proxy to
            // add chaining via super()
            if ( isFunction(source[p]) ) {

               if ( p != 'constructor' && target[p] !== source[p] ) {

                  // Break the shared scope and lock in the current method
                  // by wrapping in another function to create a new parent scope
                  target[p] = (function (_base, _call, _continue) {

                        var _super = function () { _base.apply(this, arguments); },
                            _superStop = function () { _continue = false; },
                            _superApply = function ( args ) { _base.apply(this, args); };

                        var _proxy = function () {

                           var _ret, __ret,
                               __super = this._super,
                               __superStop = this._superStop,
                               __superApply = this._superApply;

                           this._super = _super;
                           this._superApply = _superApply;
                           if ( _continue )
                              this._superStop = _superStop;

                           var _ret = _call.apply(this, arguments);

                           if ( _continue ) {
                              __ret = _super.apply(this, arguments);
                              if ( typeof(_ret) == 'undefined') _ret = __ret;
                           }

                           this._super = __super;
                           this._superApply = __superApply;
                           this._superStop = __superStop;

                           return _ret;
                        }

                        return _proxy;

                     })(target[p], source[p], ( options.functions === true || options.functions[p] ));
               }

            } else {

               // Try to merge non-functions (objects/arrays/literals).
               // source wins ties.  This is a deep copy to ensure
               // all references will be unique.
               if ( (isObject(source[p]) || isArray(source[p]) ) && (options.properties || options.properties[p]) )
                  target[p] = merge(merge(null, target[p]), source[p]);
               else
                  target[p] = source[p];

            }

         } else {

            // No collisions detected.  Copy it all across.
            target[p] = source[p];

         }
      }

      return target;
   }

   /**
   * Ensure the provided object is a "class" ( a function with a prototype set ).
   * Objects will be inspected to detemine if a constructor method is defined.
   * If so, it will be used a the function and the object will be set as the
   * prototype.  Otherwise, a generic, empty function will be created.
   *
   * @param k { Function | Object } the object to normalize
   *
   */

   var normalize = function(k) {

      var klass;

      if ( typeof(k) == 'function' ) {

         klass = k;

      } else if ( k.hasOwnProperty('constructor') ) {

         klass = k.constructor;
         klass.prototype = k;

      } else {

         klass = function () { };
         klass.prototype = k;

      }

      return klass;
   }

   /***
   *   Extend a base class (parent) with subclass defintion (child).  Optionally,
   *   merge mixin objects to the final class object.
   *   @params: 2 or more { Function | Object }
   *
   *      first argument is expected to be the parent/base class
   *
   *      last argument is expected to be the child/sub class
   *
   *      extra arguments between the first and last are
   *      assumed to be mixins.  The order is important as it
   *      determines how each function is chained to the next.
   *      the first mixin will be the last one called in the chain.
   */

   var extend = function() {

      var parent, child, proxy,
          csubr, args, len,
          auto, protos, odefs;

      //Must have at least a parent and child
      if (arguments.length < 2 ) return;

      args = [];
      if ( isObject(arguments[0]) || isFunction(arguments[0]) )
         args.push(arguments[0]);

      // Check for mixins array as second argument
      if ( isArray(arguments[1]) ) {
         args = args.concat(arguments[1]);
         args.push(arguments[2]);

         // Check for static properties
         if ( arguments.length == 4 && isObject(arguments[3]) )
            odefs = arguments[3];

      } else {
         args.push(arguments[1]);

         // Check for static properties
         if ( arguments.length == 3 && isObject(arguments[2]) )
            odefs = arguments[2];
      }

      len = args.length;
      odefs = odefs || {};

      // Reorganize the inputs to ensure all the function
      // chains are in the correct order
      // child --> mixinN --> mixin2 ... mixin1 --> parent
      // args[0] = child; args[len-1] = parent, args[1..len-1] = mixins[1..N] (precedence in reverse order)
      proxy = {};
      protos = new Array(len);
      args = [args[len-1], args[0]].concat(args.slice(1,len-1));

      for ( var k=len-1;k>=0;k-- ) {

         norm = normalize(args[k]);
         protos[k] = norm.prototype;
         if ( k == 1 )
            parent = norm;

         if ( typeof(args[k]) == 'function' || args[k].hasOwnProperty('constructor') ) {
            proxy = chain(proxy, { f: norm }, { functions: true } );
         }

      }

      // Create prototype chain from parent to child
      child = function () { proxy.f.apply(this, arguments); };

      csubr = function () { };
      csubr.prototype = parent.prototype;
      child.prototype = new csubr;

      // Attach static helpers
      // Merge with parent
      for ( var s in parent ) {
         if ( parent.hasOwnProperty(s) && !odefs[s] )
            odefs[s] = parent[s];
      }

      child = Factory(child, odefs);

      // Collisions with parent should not chain
      // automatically.  Override parents implementation
      // call _super() to execute parent's version
      auto = {};
      for ( var p in protos[0] ) {
         if ( typeof(protos[0][p]) == 'function' ) {
            auto[p] = !parent.prototype.hasOwnProperty(p);
         }
      }

      // Add mixins.  Also auto-chain collisions
      // call _superStop() to break the chain
      child.mix(protos.slice(2, len), { functions: true });

      // Finally, add child prototypes, only auto-chain
      // collisions with mixins
      child.mix([protos[0]], { functions: auto });

      return child;
   }

   // Define several convienece function to add
   // to new object definitions
   var Helpers = {

      extend: function () {
         return extend.apply(this, [this].concat(Array.prototype.slice.call(arguments)));
      },

      mix: function ( m, auto ) {

         var len = m.length;

         for ( var k=0;k<len;k++ ) {
            this.prototype = chain(this.prototype, m[k], auto);
         }
      }
   };

   var __GUID__ = 0;

   /***
   *
   *  Setup object definition with the static helpers (extend, mix)
   *  and wrap the constructor to ensure it is always called with
   *  "new".  If not, call it with new.  Also, set a unique ID
   *  on the instance to help with debugging.
   *
   *  @param k [ Object | Function ] Definition to setup.
   *
   *     The input will be normalized to a function/prototype.  Used
   *     in extend to setup new children.
   *
   *  @param s [ Object ] Static object methods/properties.
   *
   *     Attach the methods and/pr properties defined in the object
   *     to the new object definition.
   */
   var Factory = function ( k, s ) {

      var Klass = normalize(k),
          Static = s || {},
          P = Klass;

      Klass = (function () {

         var F = function (args) {

            if (!this._guid)
               this._guid = (++__GUID__);

            //console.log('instance checker:'+__GUID__);

            P.apply(this, args);
         }

         F.prototype = P.prototype;

         return function () {

            if ( this instanceof F || this._guid ) {
               F.call(this, arguments);
               return;
            }

            return new F(arguments);
         }

      })();

      Klass.prototype = P.prototype;

      Klass = merge( Klass, merge( Helpers, Static) );

      return Klass;
   }

   // Make the root object definition
   // Exposes extend() to build new object definitions
   //
   window.Base = Factory({});

})();
<commit_msg>Ensure _continue resets across _superStop calls<commit_after>/*!
 * Copyright (c) 2012 Ben Olson (https://github.com/bseth99/basejs)
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Dependancies: None
 *
 */

(function (undefined) {

   var isArray = function( v ) {
      return (v && Object.prototype.toString.call( v ) === '[object Array]');
   }

   var isObject = function( v ) {
      return (v && typeof v == 'object');
   }

   var isFunction = function( v ) {
      return (v && typeof v == 'function');
   }

   /**
   * Deep copy a source variable to a target variable.
   *
   * @param target { Any }
   * @param source ( Any }
   *
   * Any enumerable type will create a copy of source into target
   * if the intrinsic value in target is not already defined.
   * Arrays and Objects will recursively attempt to copy items from
   * source to target to fill in any missing items.
   *
   */

   var merge = function(target, source) {

      if ( typeof(source) == 'undefined' )
         return target;

      if ( isObject(source) ) {

         target = target || (isArray(source) ? [] : {});

         for ( var p in source ) {

            if ( target[p] && source[p] === target[p] )
               continue;

            target[p] = merge( target[p], source[p] );
         }

      } else {

         if ( source instanceof Date )
            target = new Date(source);
         else
            target = source;

      }

      return target;
   }

   /**
   * Look for collisions and create wrappers to setup "super" chain
   * Enables chaining method automatically or manually via _super()
   *
   * @param target { Object } receiving object.
   *        Everything in source will be copied
   *        to the target object.  Collisions in function names will be wrapped
   *        such that the function in target will be available via the _super method
   *        while the source method is executing.  If auto is true, the target method
   *        will be executed after the source method is complete.  The return value of
   *        source will be used unless its undefined in which case the return from target
   *        will be used.
   *
   * @param source { Object } properties to merge into target
   *
   * @param options { Object } how to handle method and/or property name collisions
   *        Two hash values are allowed:
   *           {
   *              functions:  { Boolean | Object } function name collisions
   *              properties: { Boolean | Object } property name collisions
   *           }
   *
   *        Both options default to true.
   *
   *        For functions, the super chain will be called automatically.
   *        For properties, Arrays and Object hashes will be merged.  The source will override the
   *        target when there is an overlap.
   *
   *        Both options also takes a Hash of keys that can indicate (true/false) if they should
   *        be auto chained / merged
   *
   *        {
   *           functions: { init: true, foo: false, bar: true },
   *           properties: false  -- never merge - just overwrite with source
   *        }
   */

   var chain = function(target, source, options) {

      var options = options || {};

      options = {
            functions: typeof(options.functions) == 'undefined' ? true : options.functions,
            properties: typeof(options.properties) == 'undefined' ? true : options.properties
         };

      for ( var p in source ) {

         // Don't merge things not actually in source (in its prototype chain)
         if ( target[p] && source.hasOwnProperty(p) ) {

            // There is a collision - wrap up the methods in a proxy to
            // add chaining via super()
            if ( isFunction(source[p]) ) {

               if ( p != 'constructor' && target[p] !== source[p] ) {

                  // Break the shared scope and lock in the current method
                  // by wrapping in another function to create a new parent scope
                  target[p] = (function (_base, _call, _continue) {

                        var __continue = _continue,
                            _super = function () { _base.apply(this, arguments); },
                            _superStop = function () { _continue = false; },
                            _superApply = function ( args ) { _base.apply(this, args); };

                        var _proxy = function () {

                           var _ret, __ret,
                               __super = this._super,
                               __superStop = this._superStop,
                               __superApply = this._superApply;

                           _continue = __continue;

                           this._super = _super;
                           this._superApply = _superApply;
                           if ( _continue )
                              this._superStop = _superStop;

                           var _ret = _call.apply(this, arguments);

                           if ( _continue ) {
                              __ret = _super.apply(this, arguments);
                              if ( typeof(_ret) == 'undefined') _ret = __ret;
                           }

                           this._super = __super;
                           this._superApply = __superApply;
                           this._superStop = __superStop;

                           return _ret;
                        }

                        return _proxy;

                     })(target[p], source[p], ( options.functions === true || options.functions[p] ));
               }

            } else {

               // Try to merge non-functions (objects/arrays/literals).
               // source wins ties.  This is a deep copy to ensure
               // all references will be unique.
               if ( (isObject(source[p]) || isArray(source[p]) ) && (options.properties || options.properties[p]) )
                  target[p] = merge(merge(null, target[p]), source[p]);
               else
                  target[p] = source[p];

            }

         } else {

            // No collisions detected.  Copy it all across.
            target[p] = source[p];

         }
      }

      return target;
   }

   /**
   * Ensure the provided object is a "class" ( a function with a prototype set ).
   * Objects will be inspected to detemine if a constructor method is defined.
   * If so, it will be used a the function and the object will be set as the
   * prototype.  Otherwise, a generic, empty function will be created.
   *
   * @param k { Function | Object } the object to normalize
   *
   */

   var normalize = function(k) {

      var klass;

      if ( typeof(k) == 'function' ) {

         klass = k;

      } else if ( k.hasOwnProperty('constructor') ) {

         klass = k.constructor;
         klass.prototype = k;

      } else {

         klass = function () { };
         klass.prototype = k;

      }

      return klass;
   }

   /***
   *   Extend a base class (parent) with subclass defintion (child).  Optionally,
   *   merge mixin objects to the final class object.
   *   @params: 2 or more { Function | Object }
   *
   *      first argument is expected to be the parent/base class
   *
   *      last argument is expected to be the child/sub class
   *
   *      extra arguments between the first and last are
   *      assumed to be mixins.  The order is important as it
   *      determines how each function is chained to the next.
   *      the first mixin will be the last one called in the chain.
   */

   var extend = function() {

      var parent, child, proxy,
          csubr, args, len,
          auto, protos, odefs;

      //Must have at least a parent and child
      if (arguments.length < 2 ) return;

      args = [];
      if ( isObject(arguments[0]) || isFunction(arguments[0]) )
         args.push(arguments[0]);

      // Check for mixins array as second argument
      if ( isArray(arguments[1]) ) {
         args = args.concat(arguments[1]);
         args.push(arguments[2]);

         // Check for static properties
         if ( arguments.length == 4 && isObject(arguments[3]) )
            odefs = arguments[3];

      } else {
         args.push(arguments[1]);

         // Check for static properties
         if ( arguments.length == 3 && isObject(arguments[2]) )
            odefs = arguments[2];
      }

      len = args.length;
      odefs = odefs || {};

      // Reorganize the inputs to ensure all the function
      // chains are in the correct order
      // child --> mixinN --> mixin2 ... mixin1 --> parent
      // args[0] = child; args[len-1] = parent, args[1..len-1] = mixins[1..N] (precedence in reverse order)
      proxy = {};
      protos = new Array(len);
      args = [args[len-1], args[0]].concat(args.slice(1,len-1));

      for ( var k=len-1;k>=0;k-- ) {

         norm = normalize(args[k]);
         protos[k] = norm.prototype;
         if ( k == 1 )
            parent = norm;

         if ( typeof(args[k]) == 'function' || args[k].hasOwnProperty('constructor') ) {
            proxy = chain(proxy, { f: norm }, { functions: true } );
         }

      }

      // Create prototype chain from parent to child
      child = function () { proxy.f.apply(this, arguments); };

      csubr = function () { };
      csubr.prototype = parent.prototype;
      child.prototype = new csubr;

      // Attach static helpers
      // Merge with parent
      for ( var s in parent ) {
         if ( parent.hasOwnProperty(s) && !odefs[s] )
            odefs[s] = parent[s];
      }

      child = Factory(child, odefs);

      // Collisions with parent should not chain
      // automatically.  Override parents implementation
      // call _super() to execute parent's version
      auto = {};
      for ( var p in protos[0] ) {
         if ( typeof(protos[0][p]) == 'function' ) {
            auto[p] = !parent.prototype.hasOwnProperty(p);
         }
      }

      // Add mixins.  Also auto-chain collisions
      // call _superStop() to break the chain
      child.mix(protos.slice(2, len), { functions: true });

      // Finally, add child prototypes, only auto-chain
      // collisions with mixins
      child.mix([protos[0]], { functions: auto });

      return child;
   }

   // Define several convienece function to add
   // to new object definitions
   var Helpers = {

      extend: function () {
         return extend.apply(this, [this].concat(Array.prototype.slice.call(arguments)));
      },

      mix: function ( m, auto ) {

         var len = m.length;

         for ( var k=0;k<len;k++ ) {
            this.prototype = chain(this.prototype, m[k], auto);
         }
      }
   };

   var __GUID__ = 0;

   /***
   *
   *  Setup object definition with the static helpers (extend, mix)
   *  and wrap the constructor to ensure it is always called with
   *  "new".  If not, call it with new.  Also, set a unique ID
   *  on the instance to help with debugging.
   *
   *  @param k [ Object | Function ] Definition to setup.
   *
   *     The input will be normalized to a function/prototype.  Used
   *     in extend to setup new children.
   *
   *  @param s [ Object ] Static object methods/properties.
   *
   *     Attach the methods and/pr properties defined in the object
   *     to the new object definition.
   */
   var Factory = function ( k, s ) {

      var Klass = normalize(k),
          Static = s || {},
          P = Klass;

      Klass = (function () {

         var F = function (args) {

            if (!this._guid)
               this._guid = (++__GUID__);

            //console.log('instance checker:'+__GUID__);

            P.apply(this, args);
         }

         F.prototype = P.prototype;

         return function () {

            if ( this instanceof F || this._guid ) {
               F.call(this, arguments);
               return;
            }

            return new F(arguments);
         }

      })();

      Klass.prototype = P.prototype;

      Klass = merge( Klass, merge( Helpers, Static) );

      return Klass;
   }

   // Make the root object definition
   // Exposes extend() to build new object definitions
   //
   window.Base = Factory({});

})();
<|endoftext|>


<commit_before>/* main.js, start the client! */
var camera, cameraControls, scene, renderer;
var sharedUniforms,
    surface, surfaceMaterial, surfaceMesh,
    ocean, oceanMaterial, oceanMesh,
    sun, sunMaterial, sunMesh,
    cloud, cloudMaterial, cloudMesh,
    atmosphere, atmosphereMaterial, atmosphereMesh;
var shaders, start;

//setTimeout(loadShaders, 2000);
loadShaders();

function loadShaders() {
  shaders = {
    surfaceVertex: 'shaders/surface_vertex.glsl',
    surfaceFragment: 'shaders/surface_fragment.glsl',
    oceanVertex: 'shaders/ocean_vertex.glsl',
    oceanFragment: 'shaders/ocean_fragment.glsl',
    cloudVertex: 'shaders/cloud_vertex.glsl',
    cloudFragment: 'shaders/cloud_fragment.glsl',
    atmosphereVertex: 'shaders/atmosphere_vertex.glsl',
    atmosphereFragment: 'shaders/atmosphere_fragment.glsl',
    classicNoise3D: 'shaders/noise/classicnoise3D.glsl',
    simplexNoise3D: 'shaders/noise/noise3D.glsl',
    classicNoise4D: 'shaders/noise/classicnoise4D.glsl',
    simplexNoise4D: 'shaders/noise/noise4D.glsl',
  };

  var numberOfShaders = _.size(shaders),
      loader = new THREE.XHRLoader(),
      onProgress = _.identity,
      onError = console.error;

  // loop through shaders, load them
  _.forEach(shaders, function loadShader(url, key) {
    loader.load(url, function shaderLoaded(shaderContent) {
      // replace shader url with shader content
      shaders[key] = shaderContent;
      numberOfShaders--;
      // all shaders are loaded, proceed to init
      if (numberOfShaders === 0) init();
    }, onProgress, onError);
  });
}

function init() {
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 100000);
  camera.position.z = 1000;

  scene = new THREE.Scene();

  var light = new THREE.PointLight(0xffffff);
  var lightPos = new THREE.Vector3(10000, 5000, 5000);
  light.position = lightPos;
  scene.add(light);

  sharedUniforms = {
    time: { // time is a float initialized to 0
      type: "f",
      value: 0.0
    },
    lightPos: {
      type: "v3",
      value: lightPos
    },
    poleSize: {
      type: "f",
      value: 0.0
    },
    oceanLevel: {
      type: "f",
      value: 0
    },
  };

  var heightSegments = 256;
  var widthSegments = heightSegments;
  var radius = 300;

  surface = new THREE.SphereBufferGeometry(radius, widthSegments, heightSegments);
  // set up materials with shaders, and prepend the
  // shaders with the shader noise functions
  surfaceMaterial = new THREE.ShaderMaterial({
    uniforms: _.extend({
      altitude: {
        type: "f",
        value: 40.0
      },
      defaultAltitude: {
        type: "f",
        value: 40.0
      },
    }, sharedUniforms),
    vertexShader: shaders.simplexNoise3D + shaders.surfaceVertex,
    fragmentShader: shaders.classicNoise3D + shaders.surfaceFragment,
    derivatives: true,
    //wireframe: true
  });
  surfaceMesh = new THREE.Mesh(surface, surfaceMaterial);

  ocean = new THREE.SphereGeometry(radius, widthSegments, heightSegments);
  // set up materials with shaders, and prepend the
  // shaders with the shader noise functions
  oceanMaterial = new THREE.ShaderMaterial({
    uniforms: _.extend({
      roughness: {
        type: "f",
        value: 1.5
      },
      intensity: {
        type: "f",
        value: 0.15
      },
    }, sharedUniforms),
    vertexShader: shaders.simplexNoise4D + shaders.oceanVertex,
    fragmentShader: shaders.simplexNoise4D + shaders.oceanFragment,
    derivatives: true,
    transparent: true,
    blending: THREE.AdditiveBlending,
    //wireframe: true
  });
  oceanMesh = new THREE.Mesh(ocean, oceanMaterial);

  cloud = new THREE.SphereBufferGeometry(radius + 50, widthSegments, heightSegments);
  // set up materials with shaders, and prepend the
  // shaders with the shader noise functions
  cloudMaterial = new THREE.ShaderMaterial({
    uniforms: _.extend({
      cloudColor: {
        type: "c",
        value: new THREE.Color(0xffffff)
      },
      cloudDensity: {
        type: "f",
        value: 0.8
      },
      cloudVariation: {
        type: "f",
        value: 0.007
      },
      cloudHeight: {
        type: "f",
        value: 16.0
      },
      cloudLimit: {
        type: "f",
        value: 0.25
      },
      cloudAnimation: {
        type: "f",
        value: 0.5
      },
    }, sharedUniforms),
    vertexShader: shaders.simplexNoise4D + shaders.cloudVertex,
    fragmentShader: shaders.simplexNoise4D + shaders.cloudFragment,
    derivatives: true,
    transparent: true,
    //wireframe: true
  });
  cloudMesh = new THREE.Mesh(cloud, cloudMaterial);

  atmosphere = new THREE.SphereBufferGeometry(radius, widthSegments, heightSegments);
  atmosphereMaterial = new THREE.ShaderMaterial({
    uniforms: _.extend({
      atmosphereColor: {
        type: "c",
        value: new THREE.Color(0xDDDD00)
      },
      atmosphereOpacity: {
        type: "f",
        value: 0.2
      },
      atmosphereAltitude: {
        type: "f",
        value: 100
      },
    }, sharedUniforms),
    vertexShader: shaders.atmosphereVertex,
    fragmentShader: shaders.atmosphereFragment,
    transparent: true
  });
  atmosphereMesh = new THREE.Mesh(atmosphere, atmosphereMaterial);

  sun = new THREE.SphereBufferGeometry(20, 10, 10);
  sun.translate(lightPos.x, lightPos.y, lightPos.z);
  //sun.translate(lightPos);
  sunMaterial = new THREE.MeshBasicMaterial({
    color: 0xffffff
  });
  sunMesh = new THREE.Mesh(sun, sunMaterial);

  scene.add(surfaceMesh);
  scene.add(oceanMesh);
  scene.add(cloudMesh);
  scene.add(atmosphereMesh);
  scene.add(sunMesh);

  // setup renderer and activate proper shader extensions
  renderer = new THREE.WebGLRenderer();
  //renderer.context.getExtension('OES_standard_derivatives');
  onWindowResize();

  cameraControls = new THREE.OrbitControls(camera, renderer.domElement);
  cameraControls.zoomSpeed = 0.1;
  cameraControls.enableKeys = false;

  var loader = document.getElementById('loader');
  loader.parentNode.removeChild(loader);
  document.getElementById('canvasContainer').appendChild(renderer.domElement);

  // start event listeners for the controls, inform them of our uniforms
  var uniforms = [surfaceMaterial.uniforms,
    sharedUniforms,
    cloudMaterial.uniforms,
    oceanMaterial.uniforms,
    atmosphereMaterial.uniforms
  ];
  var inputCtrl = new InputControl(document.getElementById("controls"), uniforms);
  inputCtrl.startGeneralListeners();
  inputCtrl.startSpecificListeners();
  inputCtrl.setupToggles();

  // lets start animating!
  start = Date.now();
  animate();
}

function animate() {
  sharedUniforms.time.value = (Date.now() - start) / 250;

  //cloudMesh.rotation.y += 0.0005;

  cameraControls.update();
  renderer.render(scene, camera);

  requestAnimationFrame(animate);
}
<commit_msg>Use window width to decide number of segments<commit_after>/* main.js, start the client! */
var camera, cameraControls, scene, renderer;
var sharedUniforms,
    surface, surfaceMaterial, surfaceMesh,
    ocean, oceanMaterial, oceanMesh,
    sun, sunMaterial, sunMesh,
    cloud, cloudMaterial, cloudMesh,
    atmosphere, atmosphereMaterial, atmosphereMesh;
var shaders, start;

//setTimeout(loadShaders, 2000);
loadShaders();

function loadShaders() {
  shaders = {
    surfaceVertex: 'shaders/surface_vertex.glsl',
    surfaceFragment: 'shaders/surface_fragment.glsl',
    oceanVertex: 'shaders/ocean_vertex.glsl',
    oceanFragment: 'shaders/ocean_fragment.glsl',
    cloudVertex: 'shaders/cloud_vertex.glsl',
    cloudFragment: 'shaders/cloud_fragment.glsl',
    atmosphereVertex: 'shaders/atmosphere_vertex.glsl',
    atmosphereFragment: 'shaders/atmosphere_fragment.glsl',
    classicNoise3D: 'shaders/noise/classicnoise3D.glsl',
    simplexNoise3D: 'shaders/noise/noise3D.glsl',
    classicNoise4D: 'shaders/noise/classicnoise4D.glsl',
    simplexNoise4D: 'shaders/noise/noise4D.glsl',
  };

  var numberOfShaders = _.size(shaders),
      loader = new THREE.XHRLoader(),
      onProgress = _.identity,
      onError = console.error;

  // loop through shaders, load them
  _.forEach(shaders, function loadShader(url, key) {
    loader.load(url, function shaderLoaded(shaderContent) {
      // replace shader url with shader content
      shaders[key] = shaderContent;
      numberOfShaders--;
      // all shaders are loaded, proceed to init
      if (numberOfShaders === 0) init();
    }, onProgress, onError);
  });
}

function init() {
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 100000);
  camera.position.z = 1000;

  scene = new THREE.Scene();

  var light = new THREE.PointLight(0xffffff);
  var lightPos = new THREE.Vector3(10000, 5000, 5000);
  light.position = lightPos;
  scene.add(light);

  sharedUniforms = {
    time: {
      type: "f",
      value: 0.0
    },
    lightPos: {
      type: "v3",
      value: lightPos
    },
    poleSize: {
      type: "f",
      value: 0.0
    },
    oceanLevel: {
      type: "f",
      value: 0
    },
  };

  var heightSegments = (window.innerWidth <= 800) ? 128 : 256;
  var widthSegments = heightSegments;
  var radius = 300;

  surface = new THREE.SphereBufferGeometry(radius, widthSegments, heightSegments);
  // set up materials with shaders, and prepend the
  // shaders with the shader noise functions
  surfaceMaterial = new THREE.ShaderMaterial({
    uniforms: _.extend({
      altitude: {
        type: "f",
        value: 40.0
      },
      defaultAltitude: {
        type: "f",
        value: 40.0
      },
    }, sharedUniforms),
    vertexShader: shaders.simplexNoise3D + shaders.surfaceVertex,
    fragmentShader: shaders.classicNoise3D + shaders.surfaceFragment,
    derivatives: true,
    //wireframe: true
  });
  surfaceMesh = new THREE.Mesh(surface, surfaceMaterial);

  ocean = new THREE.SphereGeometry(radius, widthSegments, heightSegments);
  // set up materials with shaders, and prepend the
  // shaders with the shader noise functions
  oceanMaterial = new THREE.ShaderMaterial({
    uniforms: _.extend({
      roughness: {
        type: "f",
        value: 1.5
      },
      intensity: {
        type: "f",
        value: 0.15
      },
    }, sharedUniforms),
    vertexShader: shaders.simplexNoise4D + shaders.oceanVertex,
    fragmentShader: shaders.simplexNoise4D + shaders.oceanFragment,
    derivatives: true,
    transparent: true,
    blending: THREE.AdditiveBlending,
    //wireframe: true
  });
  oceanMesh = new THREE.Mesh(ocean, oceanMaterial);

  cloud = new THREE.SphereBufferGeometry(radius + 50, widthSegments, heightSegments);
  // set up materials with shaders, and prepend the
  // shaders with the shader noise functions
  cloudMaterial = new THREE.ShaderMaterial({
    uniforms: _.extend({
      cloudColor: {
        type: "c",
        value: new THREE.Color(0xffffff)
      },
      cloudDensity: {
        type: "f",
        value: 0.8
      },
      cloudVariation: {
        type: "f",
        value: 0.007
      },
      cloudHeight: {
        type: "f",
        value: 16.0
      },
      cloudLimit: {
        type: "f",
        value: 0.25
      },
      cloudAnimation: {
        type: "f",
        value: 0.5
      },
    }, sharedUniforms),
    vertexShader: shaders.simplexNoise4D + shaders.cloudVertex,
    fragmentShader: shaders.simplexNoise4D + shaders.cloudFragment,
    derivatives: true,
    transparent: true,
    //wireframe: true
  });
  cloudMesh = new THREE.Mesh(cloud, cloudMaterial);

  atmosphere = new THREE.SphereBufferGeometry(radius, widthSegments, heightSegments);
  atmosphereMaterial = new THREE.ShaderMaterial({
    uniforms: _.extend({
      atmosphereColor: {
        type: "c",
        value: new THREE.Color(0xDDDD00)
      },
      atmosphereOpacity: {
        type: "f",
        value: 0.2
      },
      atmosphereAltitude: {
        type: "f",
        value: 100
      },
    }, sharedUniforms),
    vertexShader: shaders.atmosphereVertex,
    fragmentShader: shaders.atmosphereFragment,
    transparent: true
  });
  atmosphereMesh = new THREE.Mesh(atmosphere, atmosphereMaterial);

  sun = new THREE.SphereBufferGeometry(20, 10, 10);
  sun.translate(lightPos.x, lightPos.y, lightPos.z);
  //sun.translate(lightPos);
  sunMaterial = new THREE.MeshBasicMaterial({
    color: 0xffffff
  });
  sunMesh = new THREE.Mesh(sun, sunMaterial);

  scene.add(surfaceMesh);
  scene.add(oceanMesh);
  scene.add(cloudMesh);
  scene.add(atmosphereMesh);
  scene.add(sunMesh);

  // setup renderer and activate proper shader extensions
  renderer = new THREE.WebGLRenderer();
  //renderer.context.getExtension('OES_standard_derivatives');
  onWindowResize();

  cameraControls = new THREE.OrbitControls(camera, renderer.domElement);
  cameraControls.zoomSpeed = 0.1;
  cameraControls.enableKeys = false;

  var loader = document.getElementById('loader');
  loader.parentNode.removeChild(loader);
  document.getElementById('canvasContainer').appendChild(renderer.domElement);

  // start event listeners for the controls, inform them of our uniforms
  var uniforms = [surfaceMaterial.uniforms,
    sharedUniforms,
    cloudMaterial.uniforms,
    oceanMaterial.uniforms,
    atmosphereMaterial.uniforms
  ];
  var inputCtrl = new InputControl(document.getElementById("controls"), uniforms);
  inputCtrl.startGeneralListeners();
  inputCtrl.startSpecificListeners();
  inputCtrl.setupToggles();

  // lets start animating!
  start = Date.now();
  animate();
}

function animate() {
  sharedUniforms.time.value = (Date.now() - start) / 250;

  //cloudMesh.rotation.y += 0.0005;

  cameraControls.update();
  renderer.render(scene, camera);

  requestAnimationFrame(animate);
}
<|endoftext|>


<commit_before>/**
 * blog.js - the core of silentor
 * author: Jayin Ton
 * version: 1.5.3
 * License:Apache 2.0
 */
(function($) {
    'use strict';
    var app_name = '';
    var blog_base = '';
    var img_root = 'img';
    var markdown_root = 'p';
    //当前请求的markdown文件
    var cur_md_path = '';
    /*是否是http:// 如果是，那么这是资源文件,如果否，说明这是要处理的a标签*/
    function isAbsolute(url) {
            return url.indexOf('//') !== -1;
        }
        /*获得相对目录*/
    function getPageBase(url) {
            return url.slice(0, url.lastIndexOf('/') + 1);
        }
        /*判断加载的路径是否是markdown文件*/
    function isMarkdownFile(url) {
            return url.toLowerCase().indexOf('.md') !== -1 || url.toLowerCase().indexOf('.markdown') !== -1;
        }
        //获得markdown的文件名,用作标题
    function getMarkdownTitle(file_path) {
            if (!isMarkdownFile(file_path)) {
                return app_name;
            } else {
                var real_file_name = file_path;
                if (hasFolder(file_path)) {
                    real_file_name = file_path.slice(file_path.lastIndexOf('/') + 1, file_path.length);
                }
                return real_file_name.split('.')[0];
            }
        }
        // resolve 路径
    function resolvePath(from, to) {
            if (from[from.length - 1] == '/') {
                from = from.substring(0, from.length - 1);
            }
            var froms = from.split('/');
            var tos = to.split('/');
            if (tos[0] == '.') {
                tos.splice(0, 1);
            } else if (tos[0] == '..') {
                froms.splice(froms.length - 1, 1);
                tos.splice(0, 1);
            } else if (tos[0].indexOf('http') != -1 || tos[0].indexOf('https') != -1) {
                return to;
            } else {
                return froms.join('/') + "/" + tos.join('/');
            }
            return resolvePath(froms.join('/'), tos.join('/'));
        }
        /**
         * @param selector 选择器
         * @param  file_path 文件路径
         * @param  isSidebar 是否是左边导航栏
         * @param  baseUrl 基准url
         */
    function load(selector, file_path, isSidebar, baseUrl) {
        var baseUrl = baseUrl || blog_base;
        var isSidebar = isSidebar || false;

        var p_url = baseUrl + file_path;

        $.get(p_url, function(data) {
            marked.setOptions({
                highlight: function(code) {
                    return hljs.highlightAuto(code).value;
                }
            });
            var _selector = $(selector);
            _selector.html(marked(data));

            //处理所有href
            _selector.find('[href]').each(function() {
                var $element = $(this);
                var url = $element.attr('href');

                if (isAbsolute(url)) {
                    $element.attr('target', '_blank');
                }

                // sidebar
                if (isSidebar && isMarkdownFile(url)) {
                    $element.attr('href', '?' + url);

                }

                //main page
                if (!isAbsolute(url) && !isSidebar && isMarkdownFile(url)) {
                    var new_url = getPageBase(cur_md_path);
                    //上一级目录
                    if (url.indexOf('../') == 0) {
                        //处理相对路径
                        new_url = resolvePath(getPageBase(cur_md_path), url);
                    } else if (url.indexOf('__P__') == 0) {
                        //文章根目录`p/`下
                        new_url = url.replace('__P__/', '');
                    } else {
                        //当前目录
                        new_url = new_url + url.replace('./', '');
                    }
                    $element.attr('href', '?' + new_url);
                }
            });
            //main-page
            if (!isSidebar) {
                //change title
                var mainTitle = $('#main-page').find('h1, h2, h3, h4, h5, h6').first().text();
                $('title').text(mainTitle);

                //图片位置
                $.each(_selector.find('img'), function(index, item) {
                    var alt = $(item).attr('alt') || '';
                    if (alt.indexOf('|left') != -1) {
                        $(item).addClass('img-left');
                    } else if (alt.indexOf('|right') != -1) {
                        $(item).addClass('img-right');
                    } else {
                        $(item).addClass('img-center');
                    }
                });
            }
            //sidebar
            if (isSidebar) {
                //round avatar
                _selector.find('img').first().addClass('avatar');
                //add animation in item
                $.each(_selector.find('li'), function(index, item) {
                    $(item).addClass('sidebar-item');
                });
            }
            //处理图片链接
            $.each(_selector.find('img'), function(index, item) {
                var $e = $(item);
                if ($e.attr('src').indexOf('__IMG__') == 0) {
                    $e.attr('src', $e.attr('src').replace('__IMG__', img_root));
                } else {
                    //适配相对路径
                    var path = resolvePath(getPageBase(p_url), $e.attr('src'));
                    $e.attr('src', path);
                }
            });

        }).fail(function(err) {
            if (err.status === 404) {
                if (file_path === 'footer.md') {
                    console.log('没有找到footer.md! 建议在p/目录下建立footer.md 文件来添加底部信息！');
                    return;
                }
                load('#main-page', '404.md', false, '/' + app_name + '/');
            }
        });
    }

    function read_config(callback) {
        $.getJSON('config.json', {}, function(data) {
            app_name = data.app_name || app_name;
            img_root = data.img_root || img_root;
            var description = data.description || "";

            markdown_root = data.markdown_root || markdown_root;
            blog_base = '/' + app_name + '/' + markdown_root + '/';

            $('meta[name=description]').first().attr('content', description);
            callback();
        }).fail(function(err) {
            alert('读取配置有误');
        });
    }

    function main() {
        read_config(function() {
            //加载侧边菜单栏
            load('#sidebar-page', 'sidebar.md', true);
            load('#main-page-footer', 'footer.md');
            //加载主内容页
            if (location.search.indexOf('&') !== -1) {
                cur_md_path = location.search.slice(1, location.search.indexOf('&'));
            } else {
                cur_md_path = location.search.slice(1, location.search.length);
            }
            //部分服务器会在后面追加'/',例如：?a/b/cxx.md/
            if (cur_md_path.charAt(cur_md_path.length - 1) === '/') {
                cur_md_path = cur_md_path.slice(0, location.search.length - 2);
            }
            if (cur_md_path === '' || !isMarkdownFile(cur_md_path)) {
                load('#main-page', 'home.md');
            } else {
                load('#main-page', cur_md_path);
            }
        });
    }

    main();

})(jQuery);<commit_msg>bump to 1.5.4<commit_after>/**
 * blog.js - the core of silentor
 * author: Jayin Ton
 * version: 1.5.4
 * License:Apache 2.0
 */
(function($) {
    'use strict';
    var app_name = '';
    var blog_base = '';
    var img_root = 'img';
    var markdown_root = 'p';
    //当前请求的markdown文件
    var cur_md_path = '';
    /*是否是http:// 如果是，那么这是资源文件,如果否，说明这是要处理的a标签*/
    function isAbsolute(url) {
            return url.indexOf('//') !== -1;
        }
        /*获得相对目录*/
    function getPageBase(url) {
            return url.slice(0, url.lastIndexOf('/') + 1);
        }
        /*判断加载的路径是否是markdown文件*/
    function isMarkdownFile(url) {
            return url.toLowerCase().indexOf('.md') !== -1 || url.toLowerCase().indexOf('.markdown') !== -1;
        }
        //获得markdown的文件名,用作标题
    function getMarkdownTitle(file_path) {
            if (!isMarkdownFile(file_path)) {
                return app_name;
            } else {
                var real_file_name = file_path;
                if (hasFolder(file_path)) {
                    real_file_name = file_path.slice(file_path.lastIndexOf('/') + 1, file_path.length);
                }
                return real_file_name.split('.')[0];
            }
        }
        // resolve 路径
    function resolvePath(from, to) {
            if (from[from.length - 1] == '/') {
                from = from.substring(0, from.length - 1);
            }
            var froms = from.split('/');
            var tos = to.split('/');
            if (tos[0] == '.') {
                tos.splice(0, 1);
            } else if (tos[0] == '..') {
                froms.splice(froms.length - 1, 1);
                tos.splice(0, 1);
            } else if (tos[0].indexOf('http') != -1 || tos[0].indexOf('https') != -1) {
                return to;
            } else {
                return froms.join('/') + "/" + tos.join('/');
            }
            return resolvePath(froms.join('/'), tos.join('/'));
        }
        /**
         * @param selector 选择器
         * @param  file_path 文件路径
         * @param  isSidebar 是否是左边导航栏
         * @param  baseUrl 基准url
         */
    function load(selector, file_path, isSidebar, baseUrl) {
        var baseUrl = baseUrl || blog_base;
        var isSidebar = isSidebar || false;

        var p_url = baseUrl + file_path;

        $.get(p_url, function(data) {
            marked.setOptions({
                highlight: function(code) {
                    return hljs.highlightAuto(code).value;
                }
            });
            var _selector = $(selector);
            _selector.html(marked(data));

            //处理所有href
            _selector.find('[href]').each(function() {
                var $element = $(this);
                var url = $element.attr('href');

                if (isAbsolute(url)) {
                    $element.attr('target', '_blank');
                }

                // sidebar
                if (isSidebar && isMarkdownFile(url)) {
                    $element.attr('href', '?' + url);

                }

                //main page
                if (!isAbsolute(url) && !isSidebar && isMarkdownFile(url)) {
                    var new_url = getPageBase(cur_md_path);
                    //上一级目录
                    if (url.indexOf('../') == 0) {
                        //处理相对路径
                        new_url = resolvePath(getPageBase(cur_md_path), url);
                    } else if (url.indexOf('__P__') == 0) {
                        //文章根目录`p/`下
                        new_url = url.replace('__P__/', '');
                    } else {
                        //当前目录
                        new_url = new_url + url.replace('./', '');
                    }
                    $element.attr('href', '?' + new_url);
                }
            });
            //main-page
            if (!isSidebar) {
                //change title
                var mainTitle = $('#main-page').find('h1, h2, h3, h4, h5, h6').first().text();
                $('title').text(mainTitle);

                //图片位置
                $.each(_selector.find('img'), function(index, item) {
                    var alt = $(item).attr('alt') || '';
                    if (alt.indexOf('|left') != -1) {
                        $(item).addClass('img-left');
                    } else if (alt.indexOf('|right') != -1) {
                        $(item).addClass('img-right');
                    } else {
                        $(item).addClass('img-center');
                    }
                });
            }
            //sidebar
            if (isSidebar) {
                //round avatar
                _selector.find('img').first().addClass('avatar');
                //add animation in item
                $.each(_selector.find('li'), function(index, item) {
                    $(item).addClass('sidebar-item');
                });
            }
            //处理图片链接
            $.each(_selector.find('img'), function(index, item) {
                var $e = $(item);
                if ($e.attr('src').indexOf('__IMG__') == 0) {
                    $e.attr('src', $e.attr('src').replace('__IMG__', img_root));
                } else {
                    //适配相对路径
                    var path = resolvePath(getPageBase(p_url), $e.attr('src'));
                    $e.attr('src', path);
                }
            });

        }).fail(function(err) {
            if (err.status === 404) {
                if (file_path === 'footer.md') {
                    console.log('没有找到footer.md! 建议在p/目录下建立footer.md 文件来添加底部信息！');
                    return;
                }
                load('#main-page', '404.md', false, '/' + app_name + '/');
            }
        });
    }

    function read_config(callback) {
        $.getJSON('config.json', {}, function(data) {
            app_name = data.app_name || app_name;
            img_root = data.img_root || img_root;
            var description = data.description || "";

            markdown_root = data.markdown_root || markdown_root;
            blog_base = '/' + app_name + '/' + markdown_root + '/';

            $('meta[name=description]').first().attr('content', description);
            callback();
        }).fail(function(err) {
            alert('读取配置有误');
        });
    }

    function main() {
        read_config(function() {
            //加载侧边菜单栏
            load('#sidebar-page', 'sidebar.md', true);
            load('#main-page-footer', 'footer.md');
            //加载主内容页
            if (location.search.indexOf('&') !== -1) {
                cur_md_path = location.search.slice(1, location.search.indexOf('&'));
            } else {
                cur_md_path = location.search.slice(1, location.search.length);
            }
            //部分服务器会在后面追加'/',例如：?a/b/cxx.md/
            if (cur_md_path.charAt(cur_md_path.length - 1) === '/') {
                cur_md_path = cur_md_path.slice(0, location.search.length - 2);
            }
            if (cur_md_path === '' || !isMarkdownFile(cur_md_path)) {
                load('#main-page', 'home.md');
            } else {
                load('#main-page', cur_md_path);
            }
        });
    }

    main();

})(jQuery);<|endoftext|>