Merge branch 'master' of https://github.com/highfidelity/hifi into avatarExporterMaterials

This commit is contained in:
unknown 2019-03-07 16:19:20 -08:00
commit cbddffd63b
112 changed files with 4516 additions and 524 deletions

9
.gitignore vendored
View file

@ -99,12 +99,9 @@ tools/jsdoc/package-lock.json
# Python compile artifacts
**/__pycache__
# ignore unneeded unity project files for avatar exporter
tools/unity-avatar-exporter/Library
tools/unity-avatar-exporter/Logs
tools/unity-avatar-exporter/Packages
tools/unity-avatar-exporter/ProjectSettings
tools/unity-avatar-exporter/Temp
# ignore local unity project files for avatar exporter
tools/unity-avatar-exporter
server-console/package-lock.json
vcpkg/
/tools/nitpick/compiledResources

View file

@ -36,11 +36,6 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 26
//buildToolsVersion '27.0.3'
def appVersionCode = Integer.valueOf(VERSION_CODE ?: 1)
def appVersionName = RELEASE_NUMBER ?: "1.0"
defaultConfig {
applicationId "io.highfidelity.hifiinterface"
minSdkVersion 24

View file

@ -18,12 +18,11 @@ task renameHifiACTaskRelease(type: Copy) {
android {
compileSdkVersion 28
defaultConfig {
applicationId "io.highfidelity.questInterface"
minSdkVersion 24
targetSdkVersion 28
versionCode 1
versionCode appVersionCode
versionName appVersionName
ndk { abiFilters 'arm64-v8a' }
externalNativeBuild {

View file

@ -1016,8 +1016,8 @@
"type": "clip",
"data": {
"url": "qrc:///avatar/animations/run_fwd.fbx",
"startFrame": 0.0,
"endFrame": 21.0,
"startFrame": 1.0,
"endFrame": 22.0,
"timeScale": 1.0,
"loopFlag": true
},

View file

@ -273,11 +273,7 @@ ModalWindow {
onTriggered: {
root.result = null;
root.canceled();
// FIXME we are leaking memory to avoid a crash
// root.destroy();
root.disableFade = true
visible = false;
root.destroy();
}
}
@ -299,11 +295,7 @@ ModalWindow {
}
root.result = JSON.stringify(result);
root.selected(root.result);
// FIXME we are leaking memory to avoid a crash
// root.destroy();
root.disableFade = true
visible = false;
root.destroy();
}
}
}

View file

@ -815,7 +815,7 @@ ModalWindow {
Action {
id: cancelAction
text: "Cancel"
onTriggered: { canceled(); root.shown = false; }
onTriggered: { canceled(); root.destroy(); }
}
}

View file

@ -168,11 +168,7 @@ ModalWindow {
shortcut: "Esc"
onTriggered: {
root.canceled();
// FIXME we are leaking memory to avoid a crash
// root.destroy();
root.disableFade = true
visible = false;
root.destroy();
}
}
@ -183,11 +179,7 @@ ModalWindow {
onTriggered: {
root.result = items ? comboBox.currentText : textResult.text
root.selected(root.result);
// FIXME we are leaking memory to avoid a crash
// root.destroy();
root.disableFade = true
visible = false;
root.destroy();
}
}
}

View file

@ -40,9 +40,9 @@ Rectangle {
property string itemHref;
property string itemAuthor;
property int itemEdition: -1;
property bool hasSomethingToTradeIn: alreadyOwned && (itemEdition > 0); // i.e., don't trade in your artist's proof
property bool isTradingIn: isUpdating && hasSomethingToTradeIn;
property bool isStocking: availability === 'not for sale' && creator === Account.username;
property bool hasSomethingToTradeIn: itemEdition > 0; // i.e., don't trade in your artist's proof
property bool isTradingIn: canUpdate && hasSomethingToTradeIn;
property bool isStocking: (availability === 'not for sale') && (creator === Account.username) && !updated_item_id;
property string certificateId;
property double balanceAfterPurchase;
property bool alreadyOwned: false; // Including proofs
@ -59,8 +59,9 @@ Rectangle {
property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified();
property string referrer;
property bool isInstalled;
property bool isUpdating;
property bool canUpdate;
property string availability: "available";
property string updated_item_id: "";
property string creator: "";
property string baseAppURL;
property int currentUpdatesPage: 1;
@ -144,6 +145,7 @@ Rectangle {
}
onAvailableUpdatesResult: {
// Answers the updatable original item cert data still owned by this user that are EITHER instances of this marketplace id, or update to this marketplace id.
if (result.status !== 'success') {
console.log("Failed to get Available Updates", result.data.message);
} else {
@ -155,7 +157,7 @@ Rectangle {
if (root.itemEdition !== -1 && root.itemEdition !== parseInt(result.data.updates[i].edition_number)) {
continue;
}
root.isUpdating = true;
root.canUpdate = true;
root.baseItemName = result.data.updates[i].base_item_title;
// This CertID is the one corresponding to the base item CertID that the user already owns
root.certificateId = result.data.updates[i].certificate_id;
@ -166,7 +168,7 @@ Rectangle {
}
}
if (result.data.updates.length === 0 || root.isUpdating) {
if (result.data.updates.length === 0 || root.canUpdate) {
root.availableUpdatesReceived = true;
refreshBuyUI();
} else {
@ -178,7 +180,7 @@ Rectangle {
onUpdateItemResult: {
if (result.status !== 'success') {
failureErrorText.text = result.message;
failureErrorText.text = result.data ? (result.data.message || "Unknown Error") : JSON.stringify(result);
root.activeView = "checkoutFailure";
} else {
root.itemHref = result.data.download_url;
@ -266,13 +268,6 @@ Rectangle {
}
}
}
MouseArea {
enabled: titleBarContainer.usernameDropdownVisible;
anchors.fill: parent;
onClicked: {
titleBarContainer.usernameDropdownVisible = false;
}
}
//
// TITLE BAR END
//
@ -481,7 +476,7 @@ Rectangle {
FiraSansSemiBold {
id: itemPriceText;
text: isTradingIn ? "FREE\nUPDATE" :
(isStocking ? "Free for creator" :
(isStocking ? "Free for creator" :
((root.itemPrice === -1) ? "--" : ((root.itemPrice > 0) ? root.itemPrice : "FREE")));
// Text size
size: isTradingIn ? 20 : 26;
@ -580,7 +575,7 @@ Rectangle {
// "View in Inventory" button
HifiControlsUit.Button {
id: viewInMyPurchasesButton;
visible: isCertified && dataReady && (isUpdating ? !hasSomethingToTradeIn : alreadyOwned);
visible: isCertified && dataReady && (isTradingIn ? hasSomethingToTradeIn : alreadyOwned);
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.light;
anchors.top: buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top;
@ -588,9 +583,9 @@ Rectangle {
height: 50;
anchors.left: parent.left;
anchors.right: parent.right;
text: root.isUpdating ? "UPDATE TO THIS ITEM FOR FREE" : "VIEW THIS ITEM IN YOUR INVENTORY";
text: (canUpdate && !isTradingIn) ? "UPDATE TO THIS ITEM FOR FREE" : "VIEW THIS ITEM IN YOUR INVENTORY";
onClicked: {
if (root.isUpdating) {
if (root.canUpdate) {
sendToScript({method: 'checkout_goToPurchases', filterText: root.baseItemName});
} else {
sendToScript({method: 'checkout_goToPurchases', filterText: root.itemName});
@ -602,7 +597,11 @@ Rectangle {
HifiControlsUit.Button {
id: buyButton;
visible: isTradingIn || !alreadyOwned || isStocking || !(root.itemType === "avatar" || root.itemType === "app");
enabled: (root.balanceAfterPurchase >= 0 && dataReady) || (!root.isCertified) || root.isUpdating;
property bool checkBalance: dataReady && (root.availability === "available")
enabled: (checkBalance && (balanceAfterPurchase >= 0)) || !isCertified || isTradingIn || isStocking;
text: isTradingIn ? "Confirm Update" :
(enabled ? (viewInMyPurchasesButton.visible ? "Get It Again" : (dataReady ? "Get Item" : "--")) :
(checkBalance ? "Insufficient Funds" : availability))
color: viewInMyPurchasesButton.visible ? hifi.buttons.white : hifi.buttons.blue;
colorScheme: hifi.colorSchemes.light;
anchors.top: viewInMyPurchasesButton.visible ? viewInMyPurchasesButton.bottom :
@ -611,13 +610,6 @@ Rectangle {
height: 50;
anchors.left: parent.left;
anchors.right: parent.right;
text: isTradingIn ?
"CONFIRM UPDATE" :
(((root.isCertified) ?
(dataReady ?
((viewInMyPurchasesButton.visible && !root.isUpdating) ? "Get It Again" : "Confirm") :
"--") :
"Get Item"));
onClicked: {
if (isTradingIn) {
// If we're updating an app, the existing app needs to be uninstalled.
@ -1110,6 +1102,7 @@ Rectangle {
root.itemAuthor = result.data.creator;
root.itemType = result.data.item_type || "unknown";
root.availability = result.data.availability;
root.updated_item_id = result.data.updated_item_id || ""
root.creator = result.data.creator;
if (root.itemType === "unknown") {
root.itemHref = result.data.review_url;
@ -1209,7 +1202,7 @@ Rectangle {
buyText.text = "";
// If the user IS on the checkout page for the updated version of an owned item...
if (root.isUpdating) {
if (root.canUpdate) {
// If the user HAS already selected a specific edition to update...
if (hasSomethingToTradeIn) {
buyText.text = "By pressing \"Confirm Update\", you agree to trade in your old item for the updated item that replaces it.";

View file

@ -112,7 +112,7 @@ Rectangle {
marketplaceItem.image_url = result.data.thumbnail_url;
marketplaceItem.name = result.data.title;
marketplaceItem.likes = result.data.likes;
if(result.data.has_liked !== undefined) {
if (result.data.has_liked !== undefined) {
marketplaceItem.liked = result.data.has_liked;
}
marketplaceItem.creator = result.data.creator;
@ -122,6 +122,7 @@ Rectangle {
marketplaceItem.attributions = result.data.attributions;
marketplaceItem.license = result.data.license;
marketplaceItem.availability = result.data.availability;
marketplaceItem.updated_item_id = result.data.updated_item_id || "";
marketplaceItem.created_at = result.data.created_at;
marketplaceItemScrollView.contentHeight = marketplaceItemContent.height;
itemsList.visible = false;
@ -979,7 +980,6 @@ Rectangle {
xhr.open("GET", url);
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
console.log(xhr.responseText);
licenseText.text = xhr.responseText;
licenseInfo.visible = true;
}

View file

@ -2,7 +2,7 @@
// MarketplaceListItem.qml
// qml/hifi/commerce/marketplace
//
// MarketplaceListItem
// MarketplaceItem
//
// Created by Roxanne Skelly on 2019-01-22
// Copyright 2019 High Fidelity, Inc.
@ -34,6 +34,7 @@ Rectangle {
property var categories: []
property int price: 0
property string availability: "unknown"
property string updated_item_id: ""
property var attributions: []
property string description: ""
property string license: ""
@ -42,7 +43,6 @@ Rectangle {
property bool isLoggedIn: false;
property int edition: -1;
property bool supports3DHTML: false;
onCategoriesChanged: {
categoriesListModel.clear();
@ -52,7 +52,7 @@ Rectangle {
}
onDescriptionChanged: {
if(root.supports3DHTML) {
descriptionTextModel.clear();
descriptionTextModel.append({text: description});
@ -264,17 +264,14 @@ Rectangle {
}
height: 50
property bool isNFS: availability === "not for sale" // Note: server will say "sold out" or "invalidated" before it says NFS
property bool isMine: creator === Account.username
property bool isUpgrade: root.edition >= 0
property int costToMe: ((isMine && isNFS) || isUpgrade) ? 0 : price
property bool isAvailable: costToMe >= 0
text: isUpgrade ? "UPGRADE FOR FREE" : (isAvailable ? (costToMe || "FREE") : availability)
enabled: isAvailable
buttonGlyph: isAvailable ? (costToMe ? hifi.glyphs.hfc : "") : ""
property bool isUpdate: root.edition >= 0 // Special case of updating from a specific older item
property bool isStocking: (creator === Account.username) && (availability === "not for sale") && !updated_item_id // Note: server will say "sold out" or "invalidated" before it says NFS
property bool isFreeSpecial: isStocking || isUpdate
enabled: isFreeSpecial || (availability === 'available')
buttonGlyph: (enabled && !isUpdate && (price > 0)) ? hifi.glyphs.hfc : ""
text: isUpdate ? "UPDATE FOR FREE" : (isStocking ? "FREE STOCK" : (enabled ? (price || "FREE") : availability))
color: hifi.buttons.blue
onClicked: root.buy();
}

View file

@ -380,7 +380,7 @@ Item {
if (updateButton.visible && uninstallButton.visible) {
item.itemButtonText = "";
item.glyphSize = 20;
} else {
} else if (item) {
item.itemButtonText = "Send to Trash";
item.glyphSize = 30;
}

View file

@ -40,10 +40,6 @@ Rectangle {
source: "images/wallet-bg.jpg";
}
Component.onDestruction: {
KeyboardScriptingInterface.raised = false;
}
Connections {
target: Commerce;

View file

@ -2346,6 +2346,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
} else {
QObject::connect(webSurface.data(), &hifi::qml::OffscreenSurface::rootContextCreated, rootItemLoadedFunctor);
}
auto surfaceContext = webSurface->getSurfaceContext();
surfaceContext->setContextProperty("KeyboardScriptingInterface", DependencyManager::get<KeyboardScriptingInterface>().data());
} else {
// FIXME: the tablet should use the OffscreenQmlSurfaceCache
webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), [](OffscreenQmlSurface* webSurface) {
@ -3282,6 +3284,7 @@ void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditiona
surfaceContext->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
surfaceContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
surfaceContext->setContextProperty("Snapshot", DependencyManager::get<Snapshot>().data());
surfaceContext->setContextProperty("KeyboardScriptingInterface", DependencyManager::get<KeyboardScriptingInterface>().data());
if (setAdditionalContextProperties) {
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
@ -3292,7 +3295,6 @@ void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditiona
surfaceContext->setContextProperty("Settings", SettingsScriptingInterface::getInstance());
surfaceContext->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance());
surfaceContext->setContextProperty("KeyboardScriptingInterface", DependencyManager::get<KeyboardScriptingInterface>().data());
surfaceContext->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED
surfaceContext->setContextProperty("GlobalServices", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED

View file

@ -910,7 +910,7 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
recorder->recordFrame(FRAME_TYPE, toFrame(*this));
}
locationChanged();
locationChanged(true, false);
// if a entity-child of this avatar has moved outside of its queryAACube, update the cube and tell the entity server.
auto entityTreeRenderer = qApp->getEntities();
EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr;
@ -920,6 +920,7 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
zoneInteractionProperties = entityTreeRenderer->getZoneInteractionProperties();
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
forEachDescendant([&](SpatiallyNestablePointer object) {
locationChanged(true, false);
// we need to update attached queryAACubes in our own local tree so point-select always works
// however we don't want to flood the update pipeline with AvatarEntity updates, so we assume
// others have all info required to properly update queryAACube of AvatarEntities on their end
@ -2324,23 +2325,25 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
std::shared_ptr<QMetaObject::Connection> skeletonConnection = std::make_shared<QMetaObject::Connection>();
*skeletonConnection = QObject::connect(_skeletonModel.get(), &SkeletonModel::skeletonLoaded, [this, skeletonModelChangeCount, skeletonConnection]() {
if (skeletonModelChangeCount == _skeletonModelChangeCount) {
if (skeletonModelChangeCount == _skeletonModelChangeCount) {
if (_fullAvatarModelName.isEmpty()) {
// Store the FST file name into preferences
const auto& mapping = _skeletonModel->getGeometry()->getMapping();
if (mapping.value("name").isValid()) {
_fullAvatarModelName = mapping.value("name").toString();
}
}
if (_fullAvatarModelName.isEmpty()) {
// Store the FST file name into preferences
const auto& mapping = _skeletonModel->getGeometry()->getMapping();
if (mapping.value("name").isValid()) {
_fullAvatarModelName = mapping.value("name").toString();
}
}
initHeadBones();
_skeletonModel->setCauterizeBoneSet(_headBoneSet);
_fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl();
initAnimGraph();
_skeletonModelLoaded = true;
}
QObject::disconnect(*skeletonConnection);
initHeadBones();
_skeletonModel->setCauterizeBoneSet(_headBoneSet);
_fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl();
initAnimGraph();
initFlowFromFST();
_skeletonModelLoaded = true;
}
QObject::disconnect(*skeletonConnection);
});
saveAvatarUrl();
@ -5384,6 +5387,15 @@ void MyAvatar::useFlow(bool isActive, bool isCollidable, const QVariantMap& phys
}
}
void MyAvatar::initFlowFromFST() {
if (_skeletonModel->isLoaded()) {
auto &flowData = _skeletonModel->getHFMModel().flowData;
if (flowData.shouldInitFlow()) {
useFlow(true, flowData.shouldInitCollisions(), flowData._physicsConfig, flowData._collisionsConfig);
}
}
}
void MyAvatar::sendPacket(const QUuid& entityID, const EntityItemProperties& properties) const {
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;

View file

@ -1751,6 +1751,7 @@ private:
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
void initHeadBones();
void initAnimGraph();
void initFlowFromFST();
// Avatar Preferences
QUrl _fullAvatarURLFromPreferences;

View file

@ -89,6 +89,8 @@ glm::vec3 RayPick::intersectRayWithEntityXYPlane(const QUuid& entityID, const gl
return intersectRayWithXYPlane(origin, direction, props.getPosition(), props.getRotation(), props.getRegistrationPoint());
}
glm::vec2 RayPick::projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint, bool unNormalized) {
glm::quat invRot = glm::inverse(rotation);
glm::vec3 localPos = invRot * (worldPos - position);
@ -102,6 +104,19 @@ glm::vec2 RayPick::projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3
return pos2D;
}
glm::vec2 RayPick::projectOntoXZPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint, bool unNormalized) {
glm::quat invRot = glm::inverse(rotation);
glm::vec3 localPos = invRot * (worldPos - position);
glm::vec3 normalizedPos = (localPos / dimensions) + registrationPoint;
glm::vec2 pos2D = glm::vec2(normalizedPos.x, (1.0f - normalizedPos.z));
if (unNormalized) {
pos2D *= glm::vec2(dimensions.x, dimensions.z);
}
return pos2D;
}
glm::vec2 RayPick::projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos, bool unNormalized) {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;

View file

@ -86,6 +86,7 @@ public:
static glm::vec2 projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos, bool unNormalized = true);
static glm::vec2 projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint, bool unNormalized);
static glm::vec2 projectOntoXZPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint, bool unNoemalized);
private:
static glm::vec3 intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat& rotation, const glm::vec3& registration);

View file

@ -155,15 +155,33 @@ PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) {
const auto entityRotation = entity->getWorldOrientation();
const auto entityPosition = entity->getWorldPosition();
const auto entityType = entity->getType();
glm::vec3 normal;
glm::vec3 normal = entityRotation * Vectors::UNIT_Z;
// TODO: Use the xz projection method for Sphere and Quad.
if (entityType == EntityTypes::Gizmo) {
normal = entityRotation * Vectors::UNIT_Y;
} else {
normal = entityRotation * Vectors::UNIT_Z;
}
float distance = glm::dot(pick.position - entityPosition, normal);
if (distance < nearestTarget.distance) {
const auto entityDimensions = entity->getScaledDimensions();
const auto entityRegistrationPoint = entity->getRegistrationPoint();
glm::vec3 intersection = pick.position - (normal * distance);
glm::vec2 pos2D = RayPick::projectOntoXYPlane(intersection, entityPosition, entityRotation,
entityDimensions, entityRegistrationPoint, false);
glm::vec2 pos2D;
auto entityType = entity->getType();
if (entityType == EntityTypes::Gizmo) {
pos2D = RayPick::projectOntoXZPlane(intersection, entityPosition, entityRotation,
entityDimensions, entityRegistrationPoint, false);
} else {
pos2D = RayPick::projectOntoXYPlane(intersection, entityPosition, entityRotation,
entityDimensions, entityRegistrationPoint, false);
}
if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) {
IntersectionType type = IntersectionType::ENTITY;
if (getFilter().doesPickLocalEntities()) {

View file

@ -65,7 +65,7 @@ static const glm::vec3 KEYBOARD_TABLET_OFFSET{0.30f, -0.38f, -0.04f};
static const glm::vec3 KEYBOARD_TABLET_DEGREES_OFFSET{-45.0f, 0.0f, 0.0f};
static const glm::vec3 KEYBOARD_TABLET_LANDSCAPE_OFFSET{-0.2f, -0.27f, -0.05f};
static const glm::vec3 KEYBOARD_TABLET_LANDSCAPE_DEGREES_OFFSET{-45.0f, 0.0f, -90.0f};
static const glm::vec3 KEYBOARD_AVATAR_OFFSET{-0.6f, 0.3f, -0.7f};
static const glm::vec3 KEYBOARD_AVATAR_OFFSET{-0.3f, 0.0f, -0.7f};
static const glm::vec3 KEYBOARD_AVATAR_DEGREES_OFFSET{0.0f, 180.0f, 0.0f};
static const QString SOUND_FILE = PathUtils::resourcesUrl() + "sounds/keyboardPress.mp3";
@ -373,6 +373,12 @@ void Keyboard::raiseKeyboardAnchor(bool raise) const {
void Keyboard::scaleKeyboard(float sensorToWorldScale) {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
{
EntityItemProperties properties;
properties.setDimensions(_anchor.originalDimensions * sensorToWorldScale);
entityScriptingInterface->editEntity(_anchor.entityID, properties);
}
{
EntityItemProperties properties;
properties.setLocalPosition(_backPlate.localPosition * sensorToWorldScale);

View file

@ -204,7 +204,8 @@ QString Overlays::overlayToEntityType(const QString& type) {
#define RENAME_PROP(o, e) \
{ \
auto iter = overlayProps.find(#o); \
if (iter != overlayProps.end()) { \
if (iter != overlayProps.end() && \
!overlayProps.contains(#e)) { \
overlayProps[#e] = iter.value(); \
} \
}
@ -493,15 +494,34 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove
RENAME_PROP_CONVERT(p1, p1, [](const QVariant& v) { return vec3toVariant(glm::vec3(0.0f)); });
RENAME_PROP_CONVERT(p2, p2, [=](const QVariant& v) {
glm::vec3 position;
bool hasPosition = false;
glm::quat rotation;
bool hasRotation = false;
auto iter2 = overlayProps.find("position");
if (iter2 != overlayProps.end()) {
position = vec3FromVariant(iter2.value());
} else if (!add) {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;
position = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(id, desiredProperties).getPosition();
hasPosition = true;
}
return vec3toVariant(vec3FromVariant(v) - position);
iter2 = overlayProps.find("rotation");
if (iter2 != overlayProps.end()) {
rotation = quatFromVariant(iter2.value());
hasRotation = true;
}
if (!add && !(hasPosition && hasRotation)) {
auto entity = DependencyManager::get<EntityTreeRenderer>()->getEntity(id);
if (entity) {
if (!hasPosition) {
position = entity->getWorldPosition();
}
if (!hasRotation) {
rotation = entity->getWorldOrientation();
}
}
}
return vec3toVariant(glm::inverse(rotation) * (vec3FromVariant(v) - position));
});
RENAME_PROP(localStart, p1);

View file

@ -1066,13 +1066,6 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
if (_enableInverseKinematics) {
_animVars.set("ikOverlayAlpha", 1.0f);
_animVars.set("splineIKEnabled", true);
_animVars.set("leftHandIKEnabled", true);
_animVars.set("rightHandIKEnabled", true);
_animVars.set("leftFootIKEnabled", true);
_animVars.set("rightFootIKEnabled", true);
_animVars.set("leftFootPoleVectorEnabled", true);
_animVars.set("rightFootPoleVectorEnabled", true);
} else {
_animVars.set("ikOverlayAlpha", 0.0f);
_animVars.set("splineIKEnabled", false);
@ -1086,6 +1079,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("rightFootPoleVectorEnabled", false);
}
_lastEnableInverseKinematics = _enableInverseKinematics;
}
_lastForward = forward;
_lastPosition = worldPosition;

View file

@ -928,9 +928,9 @@ void RenderableModelEntityItem::setJointTranslationsSet(const QVector<bool>& tra
_needsJointSimulation = true;
}
void RenderableModelEntityItem::locationChanged(bool tellPhysics) {
void RenderableModelEntityItem::locationChanged(bool tellPhysics, bool tellChildren) {
DETAILED_PERFORMANCE_TIMER("locationChanged");
EntityItem::locationChanged(tellPhysics);
EntityItem::locationChanged(tellPhysics, tellChildren);
auto model = getModel();
if (model && model->isLoaded()) {
model->updateRenderItems();
@ -1032,9 +1032,7 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
});
if (changed) {
forEachChild([&](SpatiallyNestablePointer object) {
object->locationChanged(false);
});
locationChanged(false, true);
}
}

View file

@ -108,7 +108,7 @@ public:
virtual void setJointTranslations(const QVector<glm::vec3>& translations) override;
virtual void setJointTranslationsSet(const QVector<bool>& translationsSet) override;
virtual void locationChanged(bool tellPhysics = true) override;
virtual void locationChanged(bool tellPhysics = true, bool tellChildren = true) override;
virtual int getJointIndex(const QString& name) const override;
virtual QStringList getJointNames() const override;

View file

@ -150,7 +150,7 @@ public:
virtual bool addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override;
virtual void removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) override;
private:
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); }
virtual void locationChanged(bool tellPhysics = true, bool tellChildren = true) override { EntityItem::locationChanged(tellPhysics, tellChildren); notifyBoundChanged(); }
virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); notifyBoundChanged(); }
void notifyBoundChanged();
void notifyChangedRenderItem();

View file

@ -1873,7 +1873,7 @@ void EntityItem::setParentID(const QUuid& value) {
glm::vec3 EntityItem::getScaledDimensions() const {
glm::vec3 scale = getSNScale();
return _unscaledDimensions * scale;
return getUnscaledDimensions() * scale;
}
void EntityItem::setScaledDimensions(const glm::vec3& value) {
@ -2593,7 +2593,7 @@ QList<EntityDynamicPointer> EntityItem::getActionsOfType(EntityDynamicType typeT
return result;
}
void EntityItem::locationChanged(bool tellPhysics) {
void EntityItem::locationChanged(bool tellPhysics, bool tellChildren) {
requiresRecalcBoxes();
if (tellPhysics) {
_flags |= Simulation::DIRTY_TRANSFORM;
@ -2602,7 +2602,7 @@ void EntityItem::locationChanged(bool tellPhysics) {
tree->entityChanged(getThisPointer());
}
}
SpatiallyNestable::locationChanged(tellPhysics); // tell all the children, also
SpatiallyNestable::locationChanged(tellPhysics, tellChildren);
std::pair<int32_t, glm::vec4> data(_spaceIndex, glm::vec4(getWorldPosition(), _boundingRadius));
emit spaceUpdate(data);
somethingChangedNotification();

View file

@ -518,7 +518,7 @@ public:
virtual bool getMeshes(MeshProxyList& result) { return true; }
virtual void locationChanged(bool tellPhysics = true) override;
virtual void locationChanged(bool tellPhysics = true, bool tellChildren = true) override;
virtual bool getScalesWithParent() const override;

View file

@ -4209,7 +4209,7 @@ void EntityItemProperties::copySimulationRestrictedProperties(const EntityItemPo
setAcceleration(entity->getAcceleration());
}
if (!_localDimensionsChanged && !_dimensionsChanged) {
setDimensions(entity->getScaledDimensions());
setLocalDimensions(entity->getScaledDimensions());
}
}

View file

@ -2039,6 +2039,8 @@ void EntityTree::fixupNeedsParentFixups() {
Simulation::DIRTY_COLLISION_GROUP |
Simulation::DIRTY_TRANSFORM);
entityChanged(entity);
entity->locationChanged(true, false);
entity->forEachDescendant([&](SpatiallyNestablePointer object) {
if (object->getNestableType() == NestableType::Entity) {
EntityItemPointer descendantEntity = std::static_pointer_cast<EntityItem>(object);
@ -2047,8 +2049,8 @@ void EntityTree::fixupNeedsParentFixups() {
Simulation::DIRTY_TRANSFORM);
entityChanged(descendantEntity);
}
object->locationChanged(true, false);
});
entity->locationChanged(true);
// Update our parent's bounding box
bool success = false;
@ -3002,8 +3004,19 @@ void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object,
// if the queryBox has changed, tell the entity-server
EntityItemPointer entity = std::dynamic_pointer_cast<EntityItem>(object);
if (entity) {
// NOTE: we rely on side-effects of the entity->updateQueryAACube() call in the following if() conditional:
if (entity->updateQueryAACube() || force) {
bool queryAACubeChanged = false;
if (!entity->hasChildren()) {
// updateQueryAACube will also update all ancestors' AACubes, so we only need to call this for leaf nodes
queryAACubeChanged = entity->updateQueryAACube();
} else {
AACube oldCube = entity->getQueryAACube();
object->forEachChild([&](SpatiallyNestablePointer descendant) {
updateEntityQueryAACubeWorker(descendant, packetSender, moveOperator, force, tellServer);
});
queryAACubeChanged = oldCube != entity->getQueryAACube();
}
if (queryAACubeChanged || force) {
bool success;
AACube newCube = entity->getQueryAACube(success);
if (success) {
@ -3027,10 +3040,6 @@ void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object,
entityChanged(entity);
}
}
object->forEachDescendant([&](SpatiallyNestablePointer descendant) {
updateEntityQueryAACubeWorker(descendant, packetSender, moveOperator, force, tellServer);
});
}
void EntityTree::updateEntityQueryAACube(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender,

View file

@ -55,8 +55,8 @@ void LightEntityItem::setUnscaledDimensions(const glm::vec3& value) {
}
}
void LightEntityItem::locationChanged(bool tellPhysics) {
EntityItem::locationChanged(tellPhysics);
void LightEntityItem::locationChanged(bool tellPhysics, bool tellChildren) {
EntityItem::locationChanged(tellPhysics, tellChildren);
withWriteLock([&] {
_lightPropertiesChanged = true;
});

View file

@ -74,7 +74,7 @@ public:
static bool getLightsArePickable() { return _lightsArePickable; }
static void setLightsArePickable(bool value) { _lightsArePickable = value; }
virtual void locationChanged(bool tellPhysics) override;
virtual void locationChanged(bool tellPhysics, bool tellChildren) override;
virtual void dimensionsChanged() override;
bool lightPropertiesChanged() const { return _lightPropertiesChanged; }

View file

@ -85,7 +85,7 @@ public:
void setUnscaledDimensions(const glm::vec3& value) override;
bool shouldBePhysical() const override { return !isDead(); }
bool supportsDetailedIntersection() const override;
bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElementPointer& element, float& distance,

View file

@ -257,7 +257,7 @@ template <typename T> struct GpuVec3ToGlm : GpuToGlmAdapter { static T get(con
case gpu::FLOAT: view.edit<glm::fvec3>(index) = value; return true;
case gpu::NUINT8: CHECK_SIZE(glm::uint32); view.edit<glm::uint32>(index) = glm::packUnorm4x8(glm::fvec4(value,0.0f)); return true;
case gpu::UINT8: view.edit<glm::u8vec3>(index) = value; return true;
case gpu::NINT2_10_10_10: view.edit<glm::uint32>(index) = glm::packSnorm3x10_1x2(glm::fvec4(value,0.0f)); return true;
case gpu::NINT2_10_10_10: view.edit<glm::uint32>(index) = glm_packSnorm3x10_1x2(glm::fvec4(value,0.0f)); return true;
default: break;
} error("GpuVec3ToGlm::set", view, index, hint); return false;
}
@ -295,7 +295,7 @@ template <typename T> struct GpuVec4ToGlm : GpuToGlmAdapter { static T get(const
case gpu::FLOAT: view.edit<glm::fvec4>(index) = value; return true;
case gpu::HALF: CHECK_SIZE(glm::uint64); view.edit<glm::uint64_t>(index) = glm::packHalf4x16(value); return true;
case gpu::UINT8: view.edit<glm::u8vec4>(index) = value; return true;
case gpu::NINT2_10_10_10: view.edit<glm::uint32>(index) = glm::packSnorm3x10_1x2(value); return true;
case gpu::NINT2_10_10_10: view.edit<glm::uint32>(index) = glm_packSnorm3x10_1x2(value); return true;
case gpu::NUINT16: CHECK_SIZE(glm::uint64); view.edit<glm::uint64>(index) = glm::packUnorm4x16(value); return true;
case gpu::NUINT8: CHECK_SIZE(glm::uint32); view.edit<glm::uint32>(index) = glm::packUnorm4x8(value); return true;
default: break;

View file

@ -46,30 +46,6 @@ namespace buffer_helpers {
gpu::BufferView clone(const gpu::BufferView& input);
gpu::BufferView resized(const gpu::BufferView& input, glm::uint32 numElements);
inline void packNormalAndTangent(glm::vec3 normal, glm::vec3 tangent, glm::uint32& packedNormal, glm::uint32& packedTangent) {
auto absNormal = glm::abs(normal);
auto absTangent = glm::abs(tangent);
normal /= glm::max(1e-6f, glm::max(glm::max(absNormal.x, absNormal.y), absNormal.z));
tangent /= glm::max(1e-6f, glm::max(glm::max(absTangent.x, absTangent.y), absTangent.z));
normal = glm::clamp(normal, -1.0f, 1.0f);
tangent = glm::clamp(tangent, -1.0f, 1.0f);
normal *= 511.0f;
tangent *= 511.0f;
glm::detail::i10i10i10i2 normalStruct;
glm::detail::i10i10i10i2 tangentStruct;
normalStruct.data.x = fastLrintf(normal.x);
normalStruct.data.y = fastLrintf(normal.y);
normalStruct.data.z = fastLrintf(normal.z);
normalStruct.data.w = 0;
tangentStruct.data.x = fastLrintf(tangent.x);
tangentStruct.data.y = fastLrintf(tangent.y);
tangentStruct.data.z = fastLrintf(tangent.z);
tangentStruct.data.w = 0;
packedNormal = normalStruct.pack;
packedTangent = tangentStruct.pack;
}
namespace mesh {
glm::uint32 forEachVertex(const graphics::MeshPointer& mesh, std::function<bool(glm::uint32 index, const QVariantMap& attributes)> func);
bool setVertexAttributes(const graphics::MeshPointer& mesh, glm::uint32 index, const QVariantMap& attributes);

View file

@ -273,6 +273,15 @@ public:
{}
};
class FlowData {
public:
FlowData() {};
QVariantMap _physicsConfig;
QVariantMap _collisionsConfig;
bool shouldInitFlow() const { return _physicsConfig.size() > 0; }
bool shouldInitCollisions() const { return _collisionsConfig.size() > 0; }
};
/// The runtime model format.
class Model {
public:
@ -319,6 +328,7 @@ public:
QList<QString> blendshapeChannelNames;
QMap<int, glm::quat> jointRotationOffsets;
FlowData flowData;
};
};
@ -343,6 +353,7 @@ typedef hfm::Mesh HFMMesh;
typedef hfm::AnimationFrame HFMAnimationFrame;
typedef hfm::Light HFMLight;
typedef hfm::Model HFMModel;
typedef hfm::FlowData FlowData;
Q_DECLARE_METATYPE(HFMAnimationFrame)
Q_DECLARE_METATYPE(QVector<HFMAnimationFrame>)

View file

@ -20,6 +20,7 @@
#include "CalculateBlendshapeNormalsTask.h"
#include "CalculateBlendshapeTangentsTask.h"
#include "PrepareJointsTask.h"
#include "ParseFlowDataTask.h"
namespace baker {
@ -101,7 +102,7 @@ namespace baker {
class BuildModelTask {
public:
using Input = VaryingSet5<hfm::Model::Pointer, std::vector<hfm::Mesh>, std::vector<hfm::Joint>, QMap<int, glm::quat>, QHash<QString, int>>;
using Input = VaryingSet6<hfm::Model::Pointer, std::vector<hfm::Mesh>, std::vector<hfm::Joint>, QMap<int, glm::quat>, QHash<QString, int>, FlowData>;
using Output = hfm::Model::Pointer;
using JobModel = Job::ModelIO<BuildModelTask, Input, Output>;
@ -111,6 +112,7 @@ namespace baker {
hfmModelOut->joints = QVector<hfm::Joint>::fromStdVector(input.get2());
hfmModelOut->jointRotationOffsets = input.get3();
hfmModelOut->jointIndices = input.get4();
hfmModelOut->flowData = input.get5();
output = hfmModelOut;
}
};
@ -157,12 +159,15 @@ namespace baker {
// Parse material mapping
const auto materialMapping = model.addJob<ParseMaterialMappingTask>("ParseMaterialMapping", mapping);
// Parse flow data
const auto flowData = model.addJob<ParseFlowDataTask>("ParseFlowData", mapping);
// Combine the outputs into a new hfm::Model
const auto buildBlendshapesInputs = BuildBlendshapesTask::Input(blendshapesPerMeshIn, normalsPerBlendshapePerMesh, tangentsPerBlendshapePerMesh).asVarying();
const auto blendshapesPerMeshOut = model.addJob<BuildBlendshapesTask>("BuildBlendshapes", buildBlendshapesInputs);
const auto buildMeshesInputs = BuildMeshesTask::Input(meshesIn, graphicsMeshes, normalsPerMesh, tangentsPerMesh, blendshapesPerMeshOut).asVarying();
const auto meshesOut = model.addJob<BuildMeshesTask>("BuildMeshes", buildMeshesInputs);
const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut, jointsOut, jointRotationOffsets, jointIndices).asVarying();
const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut, jointsOut, jointRotationOffsets, jointIndices, flowData).asVarying();
const auto hfmModelOut = model.addJob<BuildModelTask>("BuildModel", buildModelInputs);
output = Output(hfmModelOut, materialMapping);

View file

@ -125,8 +125,8 @@ void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphics
#if HFM_PACK_NORMALS
const auto normal = normalizeDirForPacking(*normalIt);
const auto tangent = normalizeDirForPacking(*tangentIt);
const auto packedNormal = glm::packSnorm3x10_1x2(glm::vec4(normal, 0.0f));
const auto packedTangent = glm::packSnorm3x10_1x2(glm::vec4(tangent, 0.0f));
const auto packedNormal = glm_packSnorm3x10_1x2(glm::vec4(normal, 0.0f));
const auto packedTangent = glm_packSnorm3x10_1x2(glm::vec4(tangent, 0.0f));
#else
const auto packedNormal = *normalIt;
const auto packedTangent = *tangentIt;

View file

@ -0,0 +1,33 @@
//
// Created by Luis Cuenca on 5/3/2019
// Copyright 2019 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ParseFlowDataTask.h"
void ParseFlowDataTask::run(const baker::BakeContextPointer& context, const Input& mapping, Output& output) {
FlowData flowData;
static const QString FLOW_PHYSICS_FIELD = "flowPhysicsData";
static const QString FLOW_COLLISIONS_FIELD = "flowCollisionsData";
for (auto mappingIter = mapping.begin(); mappingIter != mapping.end(); mappingIter++) {
if (mappingIter.key() == FLOW_PHYSICS_FIELD || mappingIter.key() == FLOW_COLLISIONS_FIELD) {
QByteArray data = mappingIter.value().toByteArray();
QJsonObject dataObject = QJsonDocument::fromJson(data).object();
if (!dataObject.isEmpty() && dataObject.keys().size() == 1) {
QString key = dataObject.keys()[0];
if (dataObject[key].isObject()) {
QVariantMap dataMap = dataObject[key].toObject().toVariantMap();
if (mappingIter.key() == FLOW_PHYSICS_FIELD) {
flowData._physicsConfig.insert(key, dataMap);
} else {
flowData._collisionsConfig.insert(key, dataMap);
}
}
}
}
}
output = flowData;
}

View file

@ -0,0 +1,24 @@
//
// Created by Luis Cuenca on 5/3/2019
// Copyright 2019 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_ParseFlowDataTask_h
#define hifi_ParseFlowDataTask_h
#include <hfm/HFM.h>
#include "Engine.h"
class ParseFlowDataTask {
public:
using Input = QVariantHash;
using Output = FlowData;
using JobModel = baker::Job::ModelIO<ParseFlowDataTask, Input, Output>;
void run(const baker::BakeContextPointer& context, const Input& input, Output& output);
};
#endif // hifi_ParseFlowDataTask_h

View file

@ -396,7 +396,11 @@ QSharedPointer<Resource> ModelCache::createResource(const QUrl& url) {
}
QSharedPointer<Resource> ModelCache::createResourceCopy(const QSharedPointer<Resource>& resource) {
return QSharedPointer<Resource>(new GeometryDefinitionResource(*resource.staticCast<GeometryDefinitionResource>()), &Resource::deleter);
if (resource->getURL().path().toLower().endsWith(".fst")) {
return QSharedPointer<Resource>(new GeometryMappingResource(*resource.staticCast<GeometryMappingResource>()), &Resource::deleter);
} else {
return QSharedPointer<Resource>(new GeometryDefinitionResource(*resource.staticCast<GeometryDefinitionResource>()), &Resource::deleter);
}
}
GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url,

View file

@ -1656,9 +1656,9 @@ void packBlendshapeOffsetTo_Pos_F32_3xSN10_Nor_3xSN10_Tan_3xSN10(glm::uvec4& pac
packed = glm::uvec4(
glm::floatBitsToUint(len),
glm::packSnorm3x10_1x2(glm::vec4(normalizedPos, 0.0f)),
glm::packSnorm3x10_1x2(glm::vec4(unpacked.normalOffset, 0.0f)),
glm::packSnorm3x10_1x2(glm::vec4(unpacked.tangentOffset, 0.0f))
glm_packSnorm3x10_1x2(glm::vec4(normalizedPos, 0.0f)),
glm_packSnorm3x10_1x2(glm::vec4(unpacked.normalOffset, 0.0f)),
glm_packSnorm3x10_1x2(glm::vec4(unpacked.tangentOffset, 0.0f))
);
}

View file

@ -315,6 +315,42 @@ inline void glm_mat4u_mul(const glm::mat4& m1, const glm::mat4& m2, glm::mat4& r
#endif
}
//
// Fast replacement of glm::packSnorm3x10_1x2()
// The SSE2 version quantizes using round to nearest even.
// The glm version quantizes using round away from zero.
//
inline uint32_t glm_packSnorm3x10_1x2(vec4 const& v) {
union i10i10i10i2 {
struct {
int x : 10;
int y : 10;
int z : 10;
int w : 2;
} data;
uint32_t pack;
} Result;
#if GLM_ARCH & GLM_ARCH_SSE2_BIT
__m128 vclamp = _mm_min_ps(_mm_max_ps(_mm_loadu_ps((float*)&v[0]), _mm_set1_ps(-1.0f)), _mm_set1_ps(1.0f));
__m128i vpack = _mm_cvtps_epi32(_mm_mul_ps(vclamp, _mm_setr_ps(511.f, 511.f, 511.f, 1.f)));
Result.data.x = _mm_cvtsi128_si32(vpack);
Result.data.y = _mm_cvtsi128_si32(_mm_shuffle_epi32(vpack, _MM_SHUFFLE(1,1,1,1)));
Result.data.z = _mm_cvtsi128_si32(_mm_shuffle_epi32(vpack, _MM_SHUFFLE(2,2,2,2)));
Result.data.w = _mm_cvtsi128_si32(_mm_shuffle_epi32(vpack, _MM_SHUFFLE(3,3,3,3)));
#else
ivec4 const Pack(round(clamp(v, -1.0f, 1.0f) * vec4(511.f, 511.f, 511.f, 1.f)));
Result.data.x = Pack.x;
Result.data.y = Pack.y;
Result.data.z = Pack.z;
Result.data.w = Pack.w;
#endif
return Result.pack;
}
// convert float to int, using round-to-nearest-even (undefined on overflow)
inline int fastLrintf(float x) {
#if GLM_ARCH & GLM_ARCH_SSE2_BIT

View file

@ -1100,10 +1100,12 @@ void SpatiallyNestable::forEachDescendantTest(const ChildLambdaTest& actor) cons
}
}
void SpatiallyNestable::locationChanged(bool tellPhysics) {
forEachChild([&](SpatiallyNestablePointer object) {
object->locationChanged(tellPhysics);
});
void SpatiallyNestable::locationChanged(bool tellPhysics, bool tellChildren) {
if (tellChildren) {
forEachChild([&](SpatiallyNestablePointer object) {
object->locationChanged(tellPhysics, tellChildren);
});
}
}
AACube SpatiallyNestable::getMaximumAACube(bool& success) const {

View file

@ -211,7 +211,7 @@ public:
void dump(const QString& prefix = "") const;
virtual void locationChanged(bool tellPhysics = true); // called when a this object's location has changed
virtual void locationChanged(bool tellPhysics = true, bool tellChildren = true); // called when a this object's location has changed
virtual void dimensionsChanged() { _queryAACubeSet = false; } // called when a this object's dimensions have changed
virtual void parentDeleted() { } // called on children of a deleted parent

View file

@ -19,6 +19,11 @@ Script.include("/~/system/libraries/controllers.js");
var isShowingOverlays = true;
var debugOverlays = {};
var textSizeOverlay = Overlays.addOverlay("text3d", {
position: MyAvatar.position,
lineHeight: 0.1,
visible: false
});
function removeOverlays() {
// enumerate the overlays and remove them
@ -31,6 +36,8 @@ function removeOverlays() {
}
}
Overlays.deleteOverlay(textSizeOverlay);
debugOverlays = {};
}
@ -60,8 +67,6 @@ function updateOverlays() {
var overlayPosition = avatar.getJointPosition("Head");
overlayPosition.y += 1.15;
var rows = 8;
var text = avatarID + "\n"
+"--- Data from Mixer ---\n"
+"All: " + AvatarManager.getAvatarDataRate(avatarID).toFixed(2) + "kbps (" + AvatarManager.getAvatarUpdateRate(avatarID).toFixed(2) + "hz)" + "\n"
@ -85,9 +90,11 @@ function updateOverlays() {
//+" SM: " + AvatarManager.getAvatarSimulationRate(avatarID,"skeletonModel").toFixed(2) + "hz \n"
+" JD: " + AvatarManager.getAvatarSimulationRate(avatarID,"jointData").toFixed(2) + "hz \n"
var dimensions = Overlays.textSize(textSizeOverlay, text);
if (avatarID in debugOverlays) {
// keep the overlay above the current position of this avatar
Overlays.editOverlay(debugOverlays[avatarID][0], {
dimensions: { x: 1.1 * dimensions.width, y: 0.6 * dimensions.height },
position: overlayPosition,
text: text
});
@ -95,15 +102,9 @@ function updateOverlays() {
// add the overlay above this avatar
var newOverlay = Overlays.addOverlay("text3d", {
position: overlayPosition,
dimensions: {
x: 1.25,
y: rows * 0.13
},
dimensions: { x: 1.1 * dimensions.width, y: 0.6 * dimensions.height },
lineHeight: 0.1,
font:{size:0.1},
text: text,
size: 1,
scale: 0.4,
color: { red: 255, green: 255, blue: 255},
alpha: 1,
solid: true,

View file

@ -134,7 +134,7 @@ Script.include("/~/system/libraries/controllers.js");
var scaleModuleName = this.hand === RIGHT_HAND ? "RightScaleEntity" : "LeftScaleEntity";
var scaleModule = getEnabledModuleByName(scaleModuleName);
if (scaleModule.grabbedThingID || scaleModule.isReady(controllerData).active) {
if (scaleModule && (scaleModule.grabbedThingID || scaleModule.isReady(controllerData).active)) {
// we're rescaling -- don't start a grab.
return makeRunningValues(false, [], []);
}

View file

@ -247,8 +247,8 @@ Script.include("/~/system/libraries/controllers.js");
this.run = function(controllerData, deltaTime) {
this.addObjectToIgnoreList(controllerData);
var type = this.getInteractableType(controllerData, isTriggerPressed, false);
var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE;
var type = this.getInteractableType(controllerData, isTriggerPressed, false);
var laserOn = isTriggerPressed || this.parameters.handLaser.alwaysOn;
this.addObjectToIgnoreList(controllerData);

View file

@ -30,7 +30,6 @@ var CONTOLLER_SCRIPTS = [
"controllerModules/teleport.js",
"controllerModules/hudOverlayPointer.js",
"controllerModules/mouseHMD.js",
"controllerModules/scaleEntity.js",
"controllerModules/nearGrabHyperLinkEntity.js",
"controllerModules/nearTabletHighlight.js",
"controllerModules/nearGrabEntity.js",

View file

@ -1492,6 +1492,8 @@ const ENTITY_SCRIPT_STATUS = {
unloaded: "Unloaded"
};
const ENABLE_DISABLE_SELECTOR = "input, textarea, span, .dropdown dl, .color-picker";
const PROPERTY_NAME_DIVISION = {
GROUP: 0,
PROPERTY: 1,
@ -1591,8 +1593,7 @@ function disableChildren(el, selector) {
}
function enableProperties() {
enableChildren(document.getElementById("properties-list"),
"input, textarea, checkbox, .dropdown dl, .color-picker , .draggable-number.text");
enableChildren(document.getElementById("properties-list"), ENABLE_DISABLE_SELECTOR);
enableChildren(document, ".colpick");
let elLocked = getPropertyInputElement("locked");
@ -1603,8 +1604,7 @@ function enableProperties() {
}
function disableProperties() {
disableChildren(document.getElementById("properties-list"),
"input, textarea, checkbox, .dropdown dl, .color-picker, .draggable-number.text");
disableChildren(document.getElementById("properties-list"), ENABLE_DISABLE_SELECTOR);
disableChildren(document, ".colpick");
for (let pickKey in colorPickers) {
colorPickers[pickKey].colpickHide();
@ -3356,8 +3356,8 @@ function loaded() {
let shouldHide = selectedEntityProperties.certificateID !== "";
if (shouldHide) {
propertyValue = "** Certified **";
property.elInput.disabled = true;
}
property.elInput.disabled = shouldHide;
}
let isPropertyNotNumber = false;

View file

@ -176,7 +176,7 @@ WebTablet = function (url, width, dpi, hand, location, visible) {
this.homeButtonID = Overlays.addOverlay("circle3d", {
name: "homeButton",
localPosition: { x: HOME_BUTTON_X_OFFSET, y: HOME_BUTTON_Y_OFFSET, z: -HOME_BUTTON_Z_OFFSET },
localRotation: { x: 0, y: 1, z: 0, w: 0},
localRotation: Quat.fromVec3Degrees({ x: 180, y: 180, z: 0}),
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim },
solid: true,
alpha: 0.0,
@ -189,7 +189,7 @@ WebTablet = function (url, width, dpi, hand, location, visible) {
this.homeButtonHighlightID = Overlays.addOverlay("circle3d", {
name: "homeButtonHighlight",
localPosition: { x: -HOME_BUTTON_X_OFFSET, y: HOME_BUTTON_Y_OFFSET, z: -HOME_BUTTON_Z_OFFSET },
localRotation: { x: 0, y: 1, z: 0, w: 0},
localRotation: Quat.fromVec3Degrees({ x: 180, y: 180, z: 0}),
dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim },
color: {red: 255, green: 255, blue: 255},
solid: true,

View file

@ -1,4 +1,17 @@
{
"opts": {
"template": "hifi-jsdoc-template"
},
"docdash": {
"meta": {
"title": "",
"description": "",
"keyword": ""
},
"search": [true],
"collapse": [true],
"typedefs": [false]
},
"templates": {
"default": {
"outputSourceFiles": false

View file

@ -0,0 +1,61 @@
# License
Docdash is free software, licensed under the Apache License, Version 2.0 (the
"License"). Commercial and non-commercial use are permitted in compliance with
the License.
Copyright (c) 2016 Clement Moron <clenemt@gmail.com> and the
[contributors to docdash](https://github.com/clenemt/docdash/graphs/contributors).
All rights reserved.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
In addition, a copy of the License is included with this distribution.
As stated in Section 7, "Disclaimer of Warranty," of the License:
> Licensor provides the Work (and each Contributor provides its Contributions)
> on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
> express or implied, including, without limitation, any warranties or
> conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
> PARTICULAR PURPOSE. You are solely responsible for determining the
> appropriateness of using or redistributing the Work and assume any risks
> associated with Your exercise of permissions under this License.
The source code for docdash is available at:
https://github.com/clenemt/docdash
# Third-Party Software
Docdash includes or depends upon the following third-party software, either in
whole or in part. Each third-party software package is provided under its own
license.
## JSDoc 3
JSDoc 3 is free software, licensed under the Apache License, Version 2.0 (the
"License"). Commercial and non-commercial use are permitted in compliance with
the License.
Copyright (c) 2011-2016 Michael Mathews <micmath@gmail.com> and the
[contributors to JSDoc](https://github.com/jsdoc3/jsdoc/graphs/contributors).
All rights reserved.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
In addition, a copy of the License is included with this distribution.
As stated in Section 7, "Disclaimer of Warranty," of the License:
> Licensor provides the Work (and each Contributor provides its Contributions)
> on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
> express or implied, including, without limitation, any warranties or
> conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
> PARTICULAR PURPOSE. You are solely responsible for determining the
> appropriateness of using or redistributing the Work and assume any risks
> associated with Your exercise of permissions under this License.
The source code for JSDoc 3 is available at:
https://github.com/jsdoc3/jsdoc

View file

@ -0,0 +1,42 @@
# hifi-jsdoc-template
The hifi-jsdoc-template is based on the [DocDash](https://github.com/clenemt/docdash) template.
## Usage
Clone repository to your designated `jsdoc/node_modules` template directory.
In your `config.json` file, add a template option.
```json
"opts": {
"template": "node_modules/hifi-jsdoc-template"
}
```
## Sample `config.json`
```json
{
"opts": {
"template": "node_modules/hifi-jsdoc-template"
},
"docdash": {
"meta": {
"title": "",
"description": "",
"keyword": ""
},
"search": [true],
"collapse": [true],
"typedefs": [false]
},
"templates": {
"default": {
"outputSourceFiles": false
}
},
"plugins": [
"plugins/hifi",
"plugins/hifiJSONExport"
]
}
```

View file

@ -0,0 +1,59 @@
{
"_from": "docdash",
"_id": "docdash@1.0.0",
"_inBundle": false,
"_integrity": "sha512-HhK72PT4z55og8FDqskO/tTYXxU+LovRz+9pCDHLnUoPchkxjdIJidS+96LqW3CLrRdBmnkDRrcVrDFGLIluTw==",
"_location": "/docdash",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "docdash",
"name": "docdash",
"escapedName": "docdash",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/docdash/-/docdash-1.0.0.tgz",
"_shasum": "5b7df10fed3d341fc4416a8978c65ad561869d18",
"_spec": "docdash",
"_where": "D:\\hifi\\tools\\jsdoc",
"author": {
"name": "Clement Moron",
"email": "clement.moron@gmail.com"
},
"bugs": {
"url": "https://github.com/clenemt/docdash/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "A clean, responsive documentation template theme for JSDoc 3 inspired by lodash and minami",
"devDependencies": {
"browser-sync": "latest",
"jsdoc": "latest",
"watch-run": "latest"
},
"homepage": "https://github.com/clenemt/docdash#readme",
"keywords": [
"jsdoc",
"template"
],
"license": "Apache-2.0",
"main": "publish.js",
"name": "docdash",
"repository": {
"type": "git",
"url": "git+https://github.com/clenemt/docdash.git"
},
"scripts": {
"sync": "browser-sync start -s ../fixtures-doc -f ../fixtures-doc --reload-delay 1000 --no-ui --no-notify",
"test": "jsdoc -c fixtures/fixtures.conf.json",
"watch": "watch-run -d 1000 -p tmpl/**,static/** \"npm run test\""
},
"version": "1.0.0"
}

View file

@ -0,0 +1,772 @@
/*global env: true */
'use strict';
var doop = require('jsdoc/util/doop');
var fs = require('jsdoc/fs');
var helper = require('jsdoc/util/templateHelper');
var logger = require('jsdoc/util/logger');
var path = require('jsdoc/path');
var taffy = require('taffydb').taffy;
var template = require('jsdoc/template');
var util = require('util');
var htmlsafe = helper.htmlsafe;
var linkto = helper.linkto;
var resolveAuthorLinks = helper.resolveAuthorLinks;
var scopeToPunc = helper.scopeToPunc;
var hasOwnProp = Object.prototype.hasOwnProperty;
var data;
var view;
var outdir = path.normalize(env.opts.destination);
function copyFile(source, target, cb) {
var cbCalled = false;
var rd = fs.createReadStream(source);
rd.on("error", function(err) {
done(err);
});
var wr = fs.createWriteStream(target);
wr.on("error", function(err) {
done(err);
});
wr.on("close", function(ex) {
done();
});
rd.pipe(wr);
function done(err) {
if (!cbCalled) {
cb(err);
cbCalled = true;
}
}
}
function find(spec) {
return helper.find(data, spec);
}
function tutoriallink(tutorial) {
return helper.toTutorial(tutorial, null, { tag: 'em', classname: 'disabled', prefix: 'Tutorial: ' });
}
function getAncestorLinks(doclet) {
return helper.getAncestorLinks(data, doclet);
}
function hashToLink(doclet, hash) {
if ( !/^(#.+)/.test(hash) ) { return hash; }
var url = helper.createLink(doclet);
url = url.replace(/(#.+|$)/, hash);
return '<a href="' + url + '">' + hash + '</a>';
}
function needsSignature(doclet) {
var needsSig = false;
// function and class definitions always get a signature
if (doclet.kind === 'function' || doclet.kind === 'class' && !doclet.hideconstructor) {
needsSig = true;
}
// typedefs that contain functions get a signature, too
else if (doclet.kind === 'typedef' && doclet.type && doclet.type.names &&
doclet.type.names.length) {
for (var i = 0, l = doclet.type.names.length; i < l; i++) {
if (doclet.type.names[i].toLowerCase() === 'function') {
needsSig = true;
break;
}
}
}
return needsSig;
}
function getSignatureAttributes(item) {
var attributes = [];
if (item.optional) {
attributes.push('opt');
}
if (item.nullable === true) {
attributes.push('nullable');
}
else if (item.nullable === false) {
attributes.push('non-null');
}
return attributes;
}
function updateItemName(item) {
var attributes = getSignatureAttributes(item);
var itemName = item.name || '';
if (item.variable) {
itemName = '&hellip;' + itemName;
}
if (attributes && attributes.length) {
itemName = util.format( '%s<span class="signature-attributes">%s</span>', itemName,
attributes.join(', ') );
}
return itemName;
}
function addParamAttributes(params) {
return params.filter(function(param) {
return param.name && param.name.indexOf('.') === -1;
}).map(updateItemName);
}
function buildItemTypeStrings(item) {
var types = [];
if (item && item.type && item.type.names) {
item.type.names.forEach(function(name) {
types.push( linkto(name, htmlsafe(name)) );
});
}
return types;
}
function buildAttribsString(attribs) {
var attribsString = '';
if (attribs && attribs.length) {
attribsString = htmlsafe( util.format('(%s) ', attribs.join(', ')) );
}
return attribsString;
}
function addNonParamAttributes(items) {
var types = [];
items.forEach(function(item) {
types = types.concat( buildItemTypeStrings(item) );
});
return types;
}
function addSignatureParams(f) {
var params = f.params ? addParamAttributes(f.params) : [];
f.signature = util.format( '%s( %s )', (f.signature || ''), params.join(', ') );
}
function addSignatureReturns(f) {
var attribs = [];
var attribsString = '';
var returnTypes = [];
var returnTypesString = '';
// jam all the return-type attributes into an array. this could create odd results (for example,
// if there are both nullable and non-nullable return types), but let's assume that most people
// who use multiple @return tags aren't using Closure Compiler type annotations, and vice-versa.
if (f.returns) {
f.returns.forEach(function(item) {
helper.getAttribs(item).forEach(function(attrib) {
if (attribs.indexOf(attrib) === -1) {
attribs.push(attrib);
}
});
});
attribsString = buildAttribsString(attribs);
}
if (f.returns) {
returnTypes = addNonParamAttributes(f.returns);
}
if (returnTypes.length) {
returnTypesString = util.format( ' &rarr; %s{%s}', attribsString, returnTypes.join('|') );
}
f.signature = '<span class="signature">' + (f.signature || '') + '</span>' +
'<span class="type-returns">' + returnTypesString + '</span>';
}
function addSignatureTypes(f) {
var types = f.type ? buildItemTypeStrings(f) : [];
f.signature = (f.signature || '') + '<span class="type-signature">' +
(types.length ? ' :' + types.join('|') : '') + '</span>';
}
function addAttribs(f) {
var attribs = helper.getAttribs(f);
var attribsString = buildAttribsString(attribs);
f.attribs = util.format('<span class="type-signature">%s</span>', attribsString);
}
function shortenPaths(files, commonPrefix) {
Object.keys(files).forEach(function(file) {
files[file].shortened = files[file].resolved.replace(commonPrefix, '')
// always use forward slashes
.replace(/\\/g, '/');
});
return files;
}
function getPathFromDoclet(doclet) {
if (!doclet.meta) {
return null;
}
return doclet.meta.path && doclet.meta.path !== 'null' ?
path.join(doclet.meta.path, doclet.meta.filename) :
doclet.meta.filename;
}
function generate(type, title, docs, filename, resolveLinks) {
resolveLinks = resolveLinks === false ? false : true;
var docData = {
type: type,
title: title,
docs: docs
};
var outpath = path.join(outdir, filename),
html = view.render('container.tmpl', docData);
if (resolveLinks) {
html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a>
}
fs.writeFileSync(outpath, html, 'utf8');
}
function generateSourceFiles(sourceFiles, encoding) {
encoding = encoding || 'utf8';
Object.keys(sourceFiles).forEach(function(file) {
var source;
// links are keyed to the shortened path in each doclet's `meta.shortpath` property
var sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened);
helper.registerLink(sourceFiles[file].shortened, sourceOutfile);
try {
source = {
kind: 'source',
code: helper.htmlsafe( fs.readFileSync(sourceFiles[file].resolved, encoding) )
};
}
catch(e) {
logger.error('Error while generating source file %s: %s', file, e.message);
}
generate('Source', sourceFiles[file].shortened, [source], sourceOutfile, false);
});
}
/**
* Look for classes or functions with the same name as modules (which indicates that the module
* exports only that class or function), then attach the classes or functions to the `module`
* property of the appropriate module doclets. The name of each class or function is also updated
* for display purposes. This function mutates the original arrays.
*
* @private
* @param {Array.<module:jsdoc/doclet.Doclet>} doclets - The array of classes and functions to
* check.
* @param {Array.<module:jsdoc/doclet.Doclet>} modules - The array of module doclets to search.
*/
function attachModuleSymbols(doclets, modules) {
var symbols = {};
// build a lookup table
doclets.forEach(function(symbol) {
symbols[symbol.longname] = symbols[symbol.longname] || [];
symbols[symbol.longname].push(symbol);
});
return modules.map(function(module) {
if (symbols[module.longname]) {
module.modules = symbols[module.longname]
// Only show symbols that have a description. Make an exception for classes, because
// we want to show the constructor-signature heading no matter what.
.filter(function(symbol) {
return symbol.description || symbol.kind === 'class';
})
.map(function(symbol) {
symbol = doop(symbol);
if (symbol.kind === 'class' || symbol.kind === 'function' && !symbol.hideconstructor) {
symbol.name = symbol.name.replace('module:', '(require("') + '"))';
}
return symbol;
});
}
});
}
function buildMemberNav(items, itemHeading, itemsSeen, linktoFn) {
var nav = '';
if (items && items.length) {
var itemsNav = '';
items.forEach(function(item) {
var displayName;
var methods = find({kind:'function', memberof: item.longname});
var signals = find({kind:'signal', memberof: item.longname});
var members = find({kind:'member', memberof: item.longname});
var docdash = env && env.conf && env.conf.docdash || {};
var conf = env && env.conf || {};
if ( !hasOwnProp.call(item, 'longname') ) {
itemsNav += '<li>' + linktoFn('', item.name);
itemsNav += '</li>';
} else if ( !hasOwnProp.call(itemsSeen, item.longname) ) {
if (conf.templates.default.useLongnameInNav) {
displayName = item.longname;
} else {
displayName = item.name;
}
itemsNav += '<li>' + linktoFn(item.longname, displayName.replace(/\b(module|event):/g, ''));
if (docdash.static && members.find(function (m) { return m.scope === 'static'; } )) {
itemsNav += "<ul class='members'>";
members.forEach(function (member) {
if (!member.scope === 'static') return;
itemsNav += "<li data-type='member'";
if(docdash.collapse)
itemsNav += " style='display: none;'";
itemsNav += ">";
itemsNav += linkto(member.longname, member.name);
itemsNav += "</li>";
});
itemsNav += "</ul>";
}
if (methods.length) {
itemsNav += "<ul class='methods'>";
methods.forEach(function (method) {
itemsNav += "<li data-type='method'";
if(docdash.collapse)
itemsNav += " style='display: none;'";
itemsNav += ">";
itemsNav += linkto(method.longname, method.name);
itemsNav += "</li>";
});
itemsNav += "</ul>";
}
if (signals.length) {
itemsNav += "<ul class='methods'>";
signals.forEach(function (signal) {
itemsNav += "<li data-type='method'";
if(docdash.collapse)
itemsNav += " style='display: none;'";
itemsNav += ">";
itemsNav += linkto(signal.longname, signal.name);
itemsNav += "</li>";
});
itemsNav += "</ul>";
}
itemsNav += '</li>';
itemsSeen[item.longname] = true;
}
});
if (itemsNav !== '') {
nav += '<h3>' + itemHeading + '</h3><ul class="nav">' + itemsNav + '</ul>';
}
}
return nav;
}
function linktoTutorial(longName, name) {
return tutoriallink(name);
}
function linktoExternal(longName, name) {
return linkto(longName, name.replace(/(^"|"$)/g, ''));
}
/**
* Create the navigation sidebar.
* @param {object} members The members that will be used to create the sidebar.
* @param {array<object>} members.classes
* @param {array<object>} members.externals
* @param {array<object>} members.globals
* @param {array<object>} members.mixins
* @param {array<object>} members.modules
* @param {array<object>} members.namespaces
* @param {array<object>} members.tutorials
* @param {array<object>} members.events
* @param {array<object>} members.interfaces
* @return {s
ring} The HTML for the navigation sidebar.
*/
function buildNav(members) {
var nav = '<h3><a href="index.html">Home</a></h3>';
var seen = {};
var seenTutorials = {};
var docdash = env && env.conf && env.conf.docdash || {};
if(docdash.menu){
for(var menu in docdash.menu){
nav += '<h2><a ';
//add attributes
for(var attr in docdash.menu[menu]){
nav += attr+'="' + docdash.menu[menu][attr] + '" ';
}
nav += '>' + menu + '</a></h2>';
}
}
var defaultOrder = [
'Namespaces', 'Classes', 'Modules', 'Externals', 'Events', 'Mixins', 'Tutorials', 'Interfaces'
];
var order = docdash.sectionOrder || defaultOrder;
var sections = {
Namespaces: buildMemberNav(members.namespaces, 'Namespaces', seen, linkto),
Classes: buildMemberNav(members.classes, 'Classes', seen, linkto),
Modules: buildMemberNav(members.modules, 'Modules', {}, linkto),
Externals: buildMemberNav(members.externals, 'Externals', seen, linktoExternal),
Events: buildMemberNav(members.events, 'Events', seen, linkto),
Mixins: buildMemberNav(members.mixins, 'Mixins', seen, linkto),
Tutorials: buildMemberNav(members.tutorials, 'Tutorials', seenTutorials, linktoTutorial),
Interfaces: buildMemberNav(members.interfaces, 'Interfaces', seen, linkto),
};
order.forEach(member => nav += sections[member]);
if (members.globals.length) {
var globalNav = '';
members.globals.forEach(function(g) {
if ( (docdash.typedefs || g.kind !== 'typedef') && !hasOwnProp.call(seen, g.longname) ) {
globalNav += '<li>' + linkto(g.longname, g.name) + '</li>';
}
seen[g.longname] = true;
});
if (!globalNav) {
// turn the heading into a link so you can actually get to the global page
nav += '<h3>' + linkto('global', 'Global') + '</h3>';
}
else {
nav += '<h3>Globals</h3><ul>' + globalNav + '</ul>';
}
}
return nav;
}
/**
@param {TAFFY} taffyData See <http://taffydb.com/>.
@param {object} opts
@param {Tutorial} tutorials
*/
exports.publish = function(taffyData, opts, tutorials) {
var docdash = env && env.conf && env.conf.docdash || {};
data = taffyData;
var conf = env.conf.templates || {};
conf.default = conf.default || {};
var templatePath = path.normalize(opts.template);
view = new template.Template( path.join(templatePath, 'tmpl') );
// claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness
// doesn't try to hand them out later
var indexUrl = helper.getUniqueFilename('index');
// don't call registerLink() on this one! 'index' is also a valid longname
var globalUrl = helper.getUniqueFilename('global');
helper.registerLink('global', globalUrl);
// set up templating
view.layout = conf.default.layoutFile ?
path.getResourcePath(path.dirname(conf.default.layoutFile),
path.basename(conf.default.layoutFile) ) :
'layout.tmpl';
// set up tutorials for helper
helper.setTutorials(tutorials);
data = helper.prune(data);
docdash.sort !== false && data.sort('longname, version, since');
helper.addEventListeners(data);
var sourceFiles = {};
var sourceFilePaths = [];
data().each(function(doclet) {
if(docdash.removeQuotes){
if(docdash.removeQuotes === "all"){
if(doclet.name){
doclet.name = doclet.name.replace(/"/g, '');
doclet.name = doclet.name.replace(/'/g, '');
}
if(doclet.longname){
doclet.longname = doclet.longname.replace(/"/g, '');
doclet.longname = doclet.longname.replace(/'/g, '');
}
}
else if(docdash.removeQuotes === "trim"){
if(doclet.name){
doclet.name = doclet.name.replace(/^"(.*)"$/, '$1');
doclet.name = doclet.name.replace(/^'(.*)'$/, '$1');
}
if(doclet.longname){
doclet.longname = doclet.longname.replace(/^"(.*)"$/, '$1');
doclet.longname = doclet.longname.replace(/^'(.*)'$/, '$1');
}
}
}
doclet.attribs = '';
if (doclet.examples) {
doclet.examples = doclet.examples.map(function(example) {
var caption, code;
if (example && example.match(/^\s*<caption>([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i)) {
caption = RegExp.$1;
code = RegExp.$3;
}
return {
caption: caption || '',
code: code || example || ''
};
});
}
if (doclet.see) {
doclet.see.forEach(function(seeItem, i) {
doclet.see[i] = hashToLink(doclet, seeItem);
});
}
// build a list of source files
var sourcePath;
if (doclet.meta) {
sourcePath = getPathFromDoclet(doclet);
sourceFiles[sourcePath] = {
resolved: sourcePath,
shortened: null
};
if (sourceFilePaths.indexOf(sourcePath) === -1) {
sourceFilePaths.push(sourcePath);
}
}
});
// update outdir if necessary, then create outdir
var packageInfo = ( find({kind: 'package'}) || [] ) [0];
if (packageInfo && packageInfo.name) {
outdir = path.join( outdir, packageInfo.name, (packageInfo.version || '') );
}
fs.mkPath(outdir);
// copy the template's static files to outdir
var fromDir = path.join(templatePath, 'static');
var staticFiles = fs.ls(fromDir, 3);
staticFiles.forEach(function(fileName) {
var toDir = fs.toDir( fileName.replace(fromDir, outdir) );
fs.mkPath(toDir);
copyFile(fileName, path.join(toDir, path.basename(fileName)), function(err){if(err) console.err(err);});
});
// copy user-specified static files to outdir
var staticFilePaths;
var staticFileFilter;
var staticFileScanner;
if (conf.default.staticFiles) {
// The canonical property name is `include`. We accept `paths` for backwards compatibility
// with a bug in JSDoc 3.2.x.
staticFilePaths = conf.default.staticFiles.include ||
conf.default.staticFiles.paths ||
[];
staticFileFilter = new (require('jsdoc/src/filter')).Filter(conf.default.staticFiles);
staticFileScanner = new (require('jsdoc/src/scanner')).Scanner();
staticFilePaths.forEach(function(filePath) {
var extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter);
extraStaticFiles.forEach(function(fileName) {
var sourcePath = fs.toDir(filePath);
var toDir = fs.toDir( fileName.replace(sourcePath, outdir) );
fs.mkPath(toDir);
copyFile(fileName, path.join(toDir, path.basename(fileName)), function(err){if(err) console.err(err);});
});
});
}
if (sourceFilePaths.length) {
sourceFiles = shortenPaths( sourceFiles, path.commonPrefix(sourceFilePaths) );
}
data().each(function(doclet) {
var url = helper.createLink(doclet);
helper.registerLink(doclet.longname, url);
// add a shortened version of the full path
var docletPath;
if (doclet.meta) {
docletPath = getPathFromDoclet(doclet);
docletPath = sourceFiles[docletPath].shortened;
if (docletPath) {
doclet.meta.shortpath = docletPath;
}
}
});
data().each(function(doclet) {
var url = helper.longnameToUrl[doclet.longname];
if (url.indexOf('#') > -1) {
doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop();
}
else {
doclet.id = doclet.name;
}
if ( needsSignature(doclet) ) {
addSignatureParams(doclet);
addSignatureReturns(doclet);
addAttribs(doclet);
}
});
// do this after the urls have all been generated
data().each(function(doclet) {
doclet.ancestors = getAncestorLinks(doclet);
if (doclet.kind === 'member') {
addSignatureTypes(doclet);
addAttribs(doclet);
}
if (doclet.kind === 'constant') {
addSignatureTypes(doclet);
addAttribs(doclet);
doclet.kind = 'member';
}
});
var members = helper.getMembers(data);
members.tutorials = tutorials.children;
// output pretty-printed source files by default
var outputSourceFiles = conf.default && conf.default.outputSourceFiles !== false
? true
: false;
// add template helpers
view.find = find;
view.linkto = linkto;
view.resolveAuthorLinks = resolveAuthorLinks;
view.tutoriallink = tutoriallink;
view.htmlsafe = htmlsafe;
view.outputSourceFiles = outputSourceFiles;
// once for all
view.nav = buildNav(members);
attachModuleSymbols( find({ longname: {left: 'module:'} }), members.modules );
// generate the pretty-printed source files first so other pages can link to them
if (outputSourceFiles) {
generateSourceFiles(sourceFiles, opts.encoding);
}
if (members.globals.length) {
generate('', 'Global', [{kind: 'globalobj'}], globalUrl);
}
// index page displays information from package.json and lists files
var files = find({kind: 'file'});
var packages = find({kind: 'package'});
generate('', 'High Fidelity API Reference',
packages.concat(
[{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}]
).concat(files),
indexUrl);
// set up the lists that we'll use to generate pages
var classes = taffy(members.classes);
var modules = taffy(members.modules);
var namespaces = taffy(members.namespaces);
var mixins = taffy(members.mixins);
var externals = taffy(members.externals);
var interfaces = taffy(members.interfaces);
Object.keys(helper.longnameToUrl).forEach(function(longname) {
var myModules = helper.find(modules, {longname: longname});
if (myModules.length) {
generate('Module', myModules[0].name, myModules, helper.longnameToUrl[longname]);
}
var myClasses = helper.find(classes, {longname: longname});
if (myClasses.length) {
generate('Class', myClasses[0].name, myClasses, helper.longnameToUrl[longname]);
}
var myNamespaces = helper.find(namespaces, {longname: longname});
if (myNamespaces.length) {
generate('Namespace', myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]);
}
var myMixins = helper.find(mixins, {longname: longname});
if (myMixins.length) {
generate('Mixin', myMixins[0].name, myMixins, helper.longnameToUrl[longname]);
}
var myExternals = helper.find(externals, {longname: longname});
if (myExternals.length) {
generate('External', myExternals[0].name, myExternals, helper.longnameToUrl[longname]);
}
var myInterfaces = helper.find(interfaces, {longname: longname});
if (myInterfaces.length) {
generate('Interface', myInterfaces[0].name, myInterfaces, helper.longnameToUrl[longname]);
}
});
// TODO: move the tutorial functions to templateHelper.js
function generateTutorial(title, tutorial, filename) {
var tutorialData = {
title: title,
header: tutorial.title,
content: tutorial.parse(),
children: tutorial.children
};
var tutorialPath = path.join(outdir, filename);
var html = view.render('tutorial.tmpl', tutorialData);
// yes, you can use {@link} in tutorials too!
html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a>
fs.writeFileSync(tutorialPath, html, 'utf8');
}
// tutorials can have only one parent so there is no risk for loops
function saveChildren(node) {
node.children.forEach(function(child) {
generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name));
saveChildren(child);
});
}
saveChildren(tutorials);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View file

@ -0,0 +1,11 @@
function hideAllButCurrent(){
//by default all submenut items are hidden
$("nav > ul > li > ul li").hide();
//only current page (if it exists) should be opened
var file = window.location.pathname.split("/").pop();
$("nav > ul > li > a[href^='"+file+"']").parent().find("> ul li").show();
}
$( document ).ready(function() {
hideAllButCurrent();
});

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,25 @@
/*global document */
(function() {
var source = document.getElementsByClassName('prettyprint source linenums');
var i = 0;
var lineNumber = 0;
var lineId;
var lines;
var totalLines;
var anchorHash;
if (source && source[0]) {
anchorHash = document.location.hash.substring(1);
lines = source[0].getElementsByTagName('li');
totalLines = lines.length;
for (; i < totalLines; i++) {
lineNumber++;
lineId = 'line' + lineNumber;
lines[i].id = lineId;
if (lineId === anchorHash) {
lines[i].className += ' selected';
}
}
}
})();

View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View file

@ -0,0 +1,2 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com",
/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);

View file

@ -0,0 +1,28 @@
var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();

View file

@ -0,0 +1,42 @@
$( document ).ready(function() {
jQuery.expr[':'].Contains = function(a,i,m){
return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase())>=0;
};
//on search
$("#nav-search").on("keyup", function(event) {
var search = $(this).val();
if (!search) {
//no search, show all results
$("nav > ul > li").show();
if(typeof hideAllButCurrent === "function"){
//let's do what ever collapse wants to do
hideAllButCurrent();
}
else{
//menu by default should be opened
$("nav > ul > li > ul li").show();
}
}
else{
//we are searching
//show all parents
$("nav > ul > li").show();
//hide all results
$("nav > ul > li > ul li").hide();
//show results matching filter
$("nav > ul > li > ul").find("a:Contains("+search+")").parent().show();
//hide parents without children
$("nav > ul > li").each(function(){
if($(this).find("a:Contains("+search+")").length == 0 && $(this).children("ul").length === 0){
//has no child at all and does not contain text
$(this).hide();
}
else if($(this).find("a:Contains("+search+")").length == 0 && $(this).find("ul").children(':visible').length == 0){
//has no visible child and does not contain text
$(this).hide();
}
});
}
});
});

View file

@ -0,0 +1,731 @@
/*******************************************************************
****************************** Font styles *************************
********************************************************************/
@font-face{
font-family: 'Cairo';
src: url('../fonts/Cairo-Bold.ttf') format('truetype');
}
@font-face{
font-family: 'Proxima Nova';
src: url('../fonts/proximanova-regular.otf') format('opentype');
}
/*******************************************************************
**************************** General styles ************************
********************************************************************/
* {
box-sizing: border-box
}
html
{
overflow: auto;
background-color: #fff;
}
body
{
font-family: 'Proxima Nova', sans-serif;
font-size: 1rem;
line-height: 1.5;
letter-spacing: 0.5px;
margin: 1.5rem;
color: #555;
}
section
{
display: block;
background-color: #fff;
padding: 12px 24px;
margin-right: 30px;
}
/*******************************************************************
**************************** Heading styles ************************
********************************************************************/
h1, h2, h3, h4 {
font-family: "Cairo", Helvetica, sans-serif;
}
h1
{
font-size: 3.25rem;
text-align: center;
letter-spacing: 1.5px;
margin: 50px 25px 25px;
}
h2
{
font-size: 2.55rem;
margin-bottom: 12px;
}
h3
{
font-size: 1.5rem;
}
h4
{
font-size: 18px;
letter-spacing: -0.33px;
margin-bottom: 12px;
color: #4d4e53;
}
h6
{
font-size: 100%;
letter-spacing: -0.01em;
margin: 6px 0 3px 0;
font-style: italic;
}
.paramHeading, .typeDef h3.propsHeading, h3.subHeading
{
font-size: .9rem;
font-family: "Proxima Nova";
font-weight: bold;
border-bottom: solid 1px #ddd;
}
h4.name
{
margin-bottom: 0px;
padding-bottom: 0px;
}
h5, .container-overview .subsection-title
{
font-size: 13px;
font-weight: bold;
margin-bottom: 5px;
}
/*******************************************************************
**************************** Table styles **************************
********************************************************************/
table
{
width: 100%;
background-color: #fff;
border-collapse: collapse;
border-spacing: 0;
border: 1px solid #ccc;
text-align: left;
overflow: auto;
font-size: 0.9rem;
line-height: 1.5;
margin-bottom: 1.5rem;
}
table > thead {
background-color: #ddd;
border-bottom: 1px solid #ccc;
font-weight: 400;
}
table th, table td {
padding: 0.5rem;
border-left: 1px solid #ccc;
}
table tr {
border-bottom: 1px solid #ccc;
}
table tr:nth-child(even) {
background-color: #f8f8f8;
}
/*******************************************************************
****************************** Link styles *************************
********************************************************************/
a, a:visited, a:active {
color: #1694CA;
text-decoration: none;
}
article a:hover {
color: #0e6185;
text-decoration: none;
font-weight: bold;
}
/*******************************************************************
***************************** List styles **************************
********************************************************************/
article ul {
margin-bottom: 1.7em;
}
article li {
padding-bottom: 5px;
}
/*******************************************************************
********************** Navigation sidebar styles *******************
********************************************************************/
nav {
position: fixed;
top: 165px;
bottom: 0;
left: 0;
right: 0;
width: 305px;
border-right: 1px solid #ccc;
overflow-y: scroll;
padding-left: 20px;
padding-right: 20px;
box-sizing: border-box;
}
nav #nav-search {
width: 210px;
height: 30px;
padding: 5px 10px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
margin-right: 20px;
margin-top: 20px;
}
.nav-header {
position: fixed;
top: 0;
left: 0;
height: 165px;
width: 305px;
background-color: #00B4EF;
vertical-align: middle;
text-align: center;
margin-top: 0px;
}
.nav-header p {
padding-top: 15px;
}
nav h3 {
font-family: "Proxima Nova", sans-serif;
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
nav ul {
font-size: 0.9rem;
padding-left: 15px;
margin: 0;
list-style: none;
}
nav ul a, nav ul a:visited, nav ul a:active {
color: #a1a1a1;
}
nav ul ul {
padding-left: 15px;
margin: 0;
list-style: none;
}
nav ul ul li:first-child
{
padding-top: 0;
}
nav li
{
margin-top: 3px;
}
nav a:hover {
font-weight: bold;
text-decoration: none;
}
nav h2 {
margin: 0;
padding: 0;
}
nav > h2 > a {
display: block;
margin: 10px 0 -10px;
color: #606 !important;
}
/* open */
.nav-trigger:checked + label:not(.steps) .navicon:before,
.nav-trigger:checked + label:not(.steps) .navicon:after {
top: 0 !important;
}
.nav-trigger:checked + label .navicon:before,
.nav-trigger:checked + label .navicon:after {
transition: 0.5s;
}
/* Minus */
.nav-trigger:checked + label {
-webkit-transform: scale(0.75);
transform: scale(0.75);
}
/* × and + */
.nav-trigger:checked + label.plus .navicon,
.nav-trigger:checked + label.x .navicon {
background: transparent;
}
.nav-trigger:checked + label.plus .navicon:before,
.nav-trigger:checked + label.x .navicon:before {
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
background: #FFF;
}
.nav-trigger:checked + label.plus .navicon:after,
.nav-trigger:checked + label.x .navicon:after {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
background: #FFF;
}
.nav-trigger:checked + label.plus {
-webkit-transform: scale(0.75) rotate(45deg);
transform: scale(0.75) rotate(45deg);
}
.nav-trigger:checked ~ nav {
left: 0 !important;
}
.nav-trigger:checked ~ .overlay {
display: block;
}
.nav-trigger {
position: fixed;
top: 0;
clip: rect(0, 0, 0, 0);
}
/********************************************************************
***************************** Search styles **************************
*********************************************************************/
.search-input
{
font-family: 'Proxima Nova', sans-serif;
font-size: 0.9rem;
border: 1px solid #ddd;
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.06);
border-radius: 0.1875rem;
color: #3A3F3E;
width: 75%;
padding: 0.425rem;
}
/********************************************************************
***************************** Code styles ***************************
*********************************************************************/
tt, code, kbd, samp {
font-family: Consolas, Monaco, 'Andale Mono', monospace;
font-size: 0.8rem;
}
.name, .signature {
font-family: Consolas, Monaco, 'Andale Mono', monospace;
font-size: 0.8rem;
}
img {
max-width: 100%;
}
p, ul, ol, blockquote {
margin-bottom: 1em;
}
.class-description {
font-size: 130%;
line-height: 140%;
margin-bottom: 1em;
margin-top: 1em;
}
.class-description:empty {
margin: 0
}
#main {
margin-left: 350px;
margin-right: 50px;
}
header {
display: block;
padding: 0px 4px;
}
.apiLinks
{
display: block;
text-align: center;
font-size: 90%;
margin-top: -20px;
}
.variation {
display: none
}
.signature-attributes {
font-size: 60%;
color: #808080;
font-style: italic;
font-weight: lighter;
}
.container-overview {
margin-top: 25px;
}
.ancestors {
color: #999
}
.ancestors a {
color: #999 !important;
}
.availableIn
{
font-size: 0.8rem;
}
.clear {
clear: both
}
.important {
font-weight: bold;
color: #950B02;
}
.yes-def {
text-indent: -1000px
}
.type-signature {
display: none;
}
.type-returns {
color: #aaa;
}
.member
{
font-family: Consolas, Monaco, 'Andale Mono', monospace;
font-size: 16px;
}
.details {
margin-top: 6px;
border-left: 2px solid #DDD;
line-height: 20px;
font-size: 14px;
}
.details dt {
width: auto;
float: left;
padding-left: 10px;
}
.details dd {
margin-left: 70px;
margin-top: 6px;
margin-bottom: 6px;
}
.details ul {
margin: 0
}
.details ul {
list-style-type: none
}
.details pre.prettyprint {
margin: 0
}
.details .object-value {
padding-top: 0
}
.description {
margin-bottom: 1em;
margin-top: 1em;
}
.code-caption {
font-style: italic;
font-size: 107%;
margin: 0;
}
.prettyprint
{
border: 1px solid #ddd;
overflow: auto;
}
.prettyprint.source {
width: inherit;
}
.prettyprint code
{
font-size: 0.65rem;
line-height: 18px;
display: block;
padding: 4px 12px;
margin: 0;
background-color: #fff;
color: #4D4E53;
}
.prettyprint code span.line
{
display: inline-block;
}
.prettyprint.linenums
{
padding-left: 70px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.prettyprint.linenums ol
{
padding-left: 0;
}
.prettyprint.linenums li
{
border-left: 3px #ddd solid;
}
.prettyprint.linenums li.selected,
.prettyprint.linenums li.selected *
{
background-color: lightyellow;
}
.prettyprint.linenums li *
{
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
}
.params code {
white-space: pre;
}
.params .name, .props .name, .name code {
color: #4D4E53;
font-family: Consolas, Monaco, 'Andale Mono', monospace;
font-size: 100%;
}
.params td.description > p:first-child, .props td.description > p:first-child {
margin-top: 0;
padding-top: 0;
}
.params td.description > p:last-child, .props td.description > p:last-child {
margin-bottom: 0;
padding-bottom: 0;
}
span.param-type, .params td .param-type, .param-type dd {
color: #606;
font-family: Consolas, Monaco, 'Andale Mono', monospace
}
.param-type dt, .param-type dd {
display: inline-block
}
.param-type {
margin: 14px 0;
}
.disabled {
color: #454545
}
/* navicon button */
.navicon-button {
display: none;
position: relative;
padding: 2.0625rem 1.5rem;
transition: 0.25s;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
opacity: .8;
}
.navicon-button .navicon:before, .navicon-button .navicon:after {
transition: 0.25s;
}
.navicon-button:hover {
transition: 0.5s;
opacity: 1;
}
.navicon-button:hover .navicon:before, .navicon-button:hover .navicon:after {
transition: 0.25s;
}
.navicon-button:hover .navicon:before {
top: .825rem;
}
.navicon-button:hover .navicon:after {
top: -.825rem;
}
/* navicon */
.navicon {
position: relative;
width: 2.5em;
height: .3125rem;
background: #000;
transition: 0.3s;
border-radius: 2.5rem;
}
.navicon:before, .navicon:after {
display: block;
content: "";
height: .3125rem;
width: 2.5rem;
background: #000;
position: absolute;
z-index: -1;
transition: 0.3s 0.25s;
border-radius: 1rem;
}
.navicon:before {
top: .625rem;
}
.navicon:after {
top: -.625rem;
}
.overlay {
display: none;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 100%;
height: 100%;
background: hsla(0, 0%, 0%, 0.5);
z-index: 1;
}
/********************************************************************
**************************** Mobile styles **************************
*********************************************************************/
@media only screen and (min-width: 320px) and (max-width: 680px) {
body {
overflow-x: hidden;
}
nav {
background: #FFF;
width: 250px;
height: 100%;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: -250px;
z-index: 3;
padding: 0 10px;
transition: left 0.2s;
}
.navicon-button {
display: inline-block;
position: fixed;
top: 1.5em;
right: 0;
z-index: 2;
}
#main {
width: 100%;
min-width: 360px;
}
#main section {
padding: 0;
}
footer {
margin-left: 0;
}
}
/** Add a '#' to static members */
[data-type="member"] a::before {
content: '#';
display: inline-block;
margin-left: -14px;
margin-right: 5px;
}
#disqus_thread{
margin-left: 30px;
}

View file

@ -0,0 +1,132 @@
/* Tomorrow Theme */
/* Original theme - https://github.com/chriskempson/tomorrow-theme */
/* Pretty printing styles. Used with prettify.js. */
/* SPAN elements with the classes below are added by prettyprint. */
/* plain text */
.pln {
color: #4d4d4c; }
@media screen {
/* string content */
.str {
color: #718c00; }
/* a keyword */
.kwd {
color: #8959a8; }
/* a comment */
.com {
color: #8e908c; }
/* a type name */
.typ {
color: #4271ae; }
/* a literal value */
.lit {
color: #f5871f; }
/* punctuation */
.pun {
color: #4d4d4c; }
/* lisp open bracket */
.opn {
color: #4d4d4c; }
/* lisp close bracket */
.clo {
color: #4d4d4c; }
/* a markup tag name */
.tag {
color: #c82829; }
/* a markup attribute name */
.atn {
color: #f5871f; }
/* a markup attribute value */
.atv {
color: #3e999f; }
/* a declaration */
.dec {
color: #f5871f; }
/* a variable name */
.var {
color: #c82829; }
/* a function name */
.fun {
color: #4271ae; } }
/* Use higher contrast and text-weight for printable form. */
@media print, projection {
.str {
color: #060; }
.kwd {
color: #006;
font-weight: bold; }
.com {
color: #600;
font-style: italic; }
.typ {
color: #404;
font-weight: bold; }
.lit {
color: #044; }
.pun, .opn, .clo {
color: #440; }
.tag {
color: #006;
font-weight: bold; }
.atn {
color: #404; }
.atv {
color: #060; } }
/* Style */
/*
pre.prettyprint {
background: white;
font-family: Consolas, Monaco, 'Andale Mono', monospace;
font-size: 12px;
line-height: 1.5;
border: 1px solid #ccc;
padding: 10px; }
*/
/* Specify class=linenums on a pre to get line numbering */
ol.linenums {
margin-top: 0;
margin-bottom: 0; }
/* IE indents via margin-left */
li.L0,
li.L1,
li.L2,
li.L3,
li.L4,
li.L5,
li.L6,
li.L7,
li.L8,
li.L9 {
/* */ }
/* Alternate shading for lines */
li.L1,
li.L3,
li.L5,
li.L7,
li.L9 {
/* */ }

View file

@ -0,0 +1,10 @@
<?js
var data = obj;
var self = this;
?>
<?js if (data.augments && data.augments.length) { ?>
<ul><?js data.augments.forEach(function(a) { ?>
<li><?js= self.linkto(a, a) ?></li>
<?js }) ?></ul>
<?js } ?>

View file

@ -0,0 +1,283 @@
<?js
var self = this;
var isGlobalPage;
docs.forEach(function(doc, i) {
?>
<?js
// we only need to check this once
if (typeof isGlobalPage === 'undefined') {
isGlobalPage = (doc.kind === 'globalobj');
}
?>
<?js if (doc.kind === 'mainpage' || (doc.kind === 'package')) { ?>
<?js= self.partial('mainpage.tmpl', doc) ?>
<?js } else if (doc.kind === 'source') { ?>
<?js= self.partial('source.tmpl', doc) ?>
<?js } else { ?>
<div class="apiLinks"> •
<?js
var classes = self.find({kind: 'class', memberof: doc.longname});
if (!isGlobalPage && classes && classes.length) {
?>
<a href="#class">Classes</a> •
<?js } ?>
<?js
var properties = doc.properties;
if (properties && properties.length && properties.forEach) {
?>
<a href="#props">Properties</a> •
<?js } ?>
<?js
var methods = self.find({kind: 'function', memberof: isGlobalPage ? {isUndefined: true} : doc.longname});
if (methods && methods.length && methods.forEach) {
?>
<a href="#method">Methods</a> •
<?js } ?>
<?js
var signals = self.find({kind: 'signal', memberof: isGlobalPage ? {isUndefined: true} : doc.longname});
if (signals && signals.length && signals.forEach) {
?>
<a href="#signal">Signals</a> •
<?js } ?>
<?js
var typedefs = self.find({kind: 'typedef', memberof: isGlobalPage ? {isUndefined: true} : doc.longname});
if (typedefs && typedefs.length && typedefs.forEach) {
?>
<a href="#typeDef">Type Definitions</a> •
<?js } ?>
<?js
var methods = self.find({kind: 'function', memberof: isGlobalPage ? {isUndefined: true} : doc.longname});
if (methods && methods.length && methods.forEach) {
?>
<a href="#methodDetails">Method Details</a> •
<?js } ?>
<?js
var signals = self.find({kind: 'signal', memberof: isGlobalPage ? {isUndefined: true} : doc.longname});
if (signals && signals.length && signals.forEach) {
?>
<a href="#signalDetails">Signal Details</a> •
<?js } ?>
</div>
<section>
<article>
<div class="container-overview">
<?js if (doc.kind === 'module' && doc.modules) { ?>
<?js if (doc.description) { ?>
<h3>Description</h3>
<p><?js= doc.description ?></p>
<?js } ?>
<?js doc.modules.forEach(function(module) { ?>
<?js= self.partial('methodList.tmpl', module) ?>
<?js }) ?>
<?js } else if (doc.kind === 'class' || (doc.kind === 'namespace' && doc.signature)) { ?>
<h3>Description</h3>
<p><?js= doc.description ?></p>
<table>
<thead>
<tr>
<th class="memberHeading">Constructor</th>
</tr>
</thead>
<tbody>
<tr>
<td><code><?js= (doc.kind === 'class' ? 'new ' : '') + doc.name + (doc.signature || '') ?></code><p />
<?js if (doc.params) { ?>
<h3 class="paramHeading">Parameters</h3>
<?js= self.partial('params.tmpl', doc.params) ?>
<?js } ?>
</tr>
</tbody>
</table>
<?js= self.partial('details.tmpl', doc) ?>
<?js } else { ?>
<h3>Description</h3>
<?js if (doc.description) { ?>
<p><?js= doc.description ?></p>
<?js } ?>
<?js
var classes = self.find({kind: 'class', memberof: doc.longname});
if (!isGlobalPage && classes && classes.length) {
?>
<h3 id="#class">Classes</h3>
<?js classes.forEach(function(c) { ?>
<p><?js= self.linkto(c.longname, c.name) ?></p>
<?js }); ?>
<?js } ?>
<?js= self.partial('details.tmpl', doc) ?>
<?js if (doc.examples && doc.examples.length) { ?>
<h3>Example<?js= doc.examples.length > 1? 's':'' ?></h3>
<?js= self.partial('examples.tmpl', doc.examples) ?>
<?js } ?>
<?js } ?>
</div>
<?js if (doc.augments && doc.augments.length) { ?>
<h3 class="subsection-title">Extends</h3>
<?js= self.partial('augments.tmpl', doc) ?>
<?js } ?>
<?js if (doc.requires && doc.requires.length) { ?>
<h3 class="subsection-title">Requires</h3>
<ul><?js doc.requires.forEach(function(r) { ?>
<li><?js= self.linkto(r, r) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js
var interfaces = self.find({kind: 'interface', memberof: doc.longname});
if (!isGlobalPage && interfaces && interfaces.length) {
?>
<h3 class="subsection-title">Interfaces</h3>
<dl><?js interfaces.forEach(function(i) { ?>
<dt><?js= self.linkto(i.longname, i.name) ?></dt>
<dd><?js if (i.summary) { ?><?js= i.summary ?><?js } ?></dd>
<?js }); ?></dl>
<?js } ?>
<?js
var mixins = self.find({kind: 'mixin', memberof: doc.longname});
if (!isGlobalPage && mixins && mixins.length) {
?>
<h3 class="subsection-title">Mixins</h3>
<dl><?js mixins.forEach(function(m) { ?>
<dt><?js= self.linkto(m.longname, m.name) ?></dt>
<dd><?js if (m.summary) { ?><?js= m.summary ?><?js } ?></dd>
<?js }); ?></dl>
<?js } ?>
<?js
var namespaces = self.find({kind: 'namespace', memberof: doc.longname});
if (!isGlobalPage && namespaces && namespaces.length) {
?>
<h3 class="subsection-title">Namespaces</h3>
<dl><?js namespaces.forEach(function(n) { ?>
<dt><?js= self.linkto(n.longname, n.name) ?></dt>
<dd><?js if (n.summary) { ?><?js= n.summary ?><?js } ?></dd>
<?js }); ?></dl>
<?js } ?>
<?js
var members = self.find({kind: 'member', memberof: isGlobalPage ? {isUndefined: true} : doc.longname});
// symbols that are assigned to module.exports are not globals, even though they're not a memberof anything
if (isGlobalPage && members && members.length && members.forEach) {
members = members.filter(function(m) {
return m.longname && m.longname.indexOf('module:') !== 0;
});
}
if (members && members.length && members.forEach) {
?>
<h3 class="subsection-title">Members</h3>
<?js members.forEach(function(p) { ?>
<?js= self.partial('members.tmpl', p) ?>
<?js }); ?>
<?js } ?>
<?js
var methods = self.find({kind: 'function', memberof: isGlobalPage ? {isUndefined: true} : doc.longname});
if (methods && methods.length && methods.forEach) {
?>
<h3 id="method">Methods</h3>
<table>
<thead>
<tr>
<th class="first">Name</th>
<th class="type">Return Value</th>
<th class="last">Summary</th>
</tr>
</thead>
<tbody>
<?js methods.forEach(function(m) { ?>
<?js= self.partial('methodList.tmpl', m) ?>
<?js }); ?>
</tbody>
</table>
<?js } ?>
<?js
var signals = self.find({kind: 'signal', memberof: isGlobalPage ? {isUndefined: true} : doc.longname});
if (signals && signals.length && signals.forEach) {
?>
<h3 id="signal">Signals</h3>
<table>
<thead>
<tr>
<th class="first">Name</th>
<th class="last">Summary</th>
</tr>
</thead>
<tbody>
<?js signals.forEach(function(m) { ?>
<?js= self.partial('signalList.tmpl', m) ?>
<?js }); ?>
</tbody>
</table>
<?js } ?>
<?js
var typedefs = self.find({kind: 'typedef', memberof: isGlobalPage ? {isUndefined: true} : doc.longname});
if (typedefs && typedefs.length && typedefs.forEach) {
?>
<div class="typeDef">
<h3 id="typeDef">Type Definitions</h3>
<?js typedefs.forEach(function(e) {
if (e.signature) {
?>
<?js= self.partial('members.tmpl', e) ?>
<?js
}
else {
?>
<?js= self.partial('members.tmpl', e) ?>
<?js
}
}); ?>
</div>
<?js } ?>
<?js
var methods = self.find({kind: 'function', memberof: isGlobalPage ? {isUndefined: true} : doc.longname});
if (methods && methods.length && methods.forEach) {
?>
<div class="methodDetails">
<h3 id="methodDetails">Method Details</h3>
<?js methods.forEach(function(m) { ?>
<?js= self.partial('method.tmpl', m) ?>
<?js }); ?>
<?js } ?>
<?js
var signals = self.find({kind: 'signal', memberof: isGlobalPage ? {isUndefined: true} : doc.longname});
if (signals && signals.length && signals.forEach) {
?>
<div class="methodDetails">
<h3 id="signalDetails">Signal Details</h3>
<?js signals.forEach(function(s) { ?>
<?js= self.partial('signal.tmpl', s) ?>
<?js }); ?>
<?js } ?>
</article>
</section>
<?js } ?>
<?js }); ?>

View file

@ -0,0 +1,143 @@
<?js
var data = obj;
var self = this;
var defaultObjectClass = '';
// Check if the default value is an object or array; if so, apply code highlighting
if (data.defaultvalue && (data.defaultvaluetype === 'object' || data.defaultvaluetype === 'array')) {
data.defaultvalue = "<pre class=\"prettyprint\"><code>" + data.defaultvalue + "</code></pre>";
defaultObjectClass = ' class="object-value"';
}
?>
<?js if (data.deprecated) { ?>
<p class="important">Deprecated: <?js
if (data.deprecated === true) { ?>Yes</p><?js }
else { ?><?js= data.deprecated ?></p><?js }
?>
<?js } ?>
<?js
var properties = data.properties;
if (properties && properties.length && properties.forEach && !data.hideconstructor) {
?>
<h3 class="propsHeading" id="props">Properties</h3>
<?js= this.partial('properties.tmpl', data) ?>
<?js } ?>
<?js if (data.version) {?>
<p>Version:</p>
<p><ul class="dummy"><li><?js= version ?></li></ul></p>
<?js } ?>
<?js if (data.since) {?>
<p>Since:</p>
<p><ul class="dummy"><li><?js= since ?></li></ul></p>
<?js } ?>
<?js if (data.inherited && data.inherits && !data.overrides) { ?>
<p>Inherited From:</p>
<p><ul class="dummy"><li>
<?js= this.linkto(data.inherits, this.htmlsafe(data.inherits)) ?>
</li></ul></p>
<?js } ?>
<?js if (data.overrides) { ?>
<p>Overrides:</p>
<p><ul class="dummy"><li>
<?js= this.linkto(data.overrides, this.htmlsafe(data.overrides)) ?>
</li></ul></p>
<?js } ?>
<?js if (data.implementations && data.implementations.length) { ?>
<p>Implementations:</p>
<p><ul>
<?js data.implementations.forEach(function(impl) { ?>
<li><?js= self.linkto(impl, self.htmlsafe(impl)) ?></li>
<?js }); ?>
</ul></p>
<?js } ?>
<?js if (data.implements && data.implements.length) { ?>
<p>Implements:</p>
<p><ul>
<?js data.implements.forEach(function(impl) { ?>
<li><?js= self.linkto(impl, self.htmlsafe(impl)) ?></li>
<?js }); ?>
</ul></p>
<?js } ?>
<?js if (data.mixes && data.mixes.length) { ?>
<p>Mixes In:</p>
<p><ul>
<?js data.mixes.forEach(function(a) { ?>
<li><?js= self.linkto(a, a) ?></li>
<?js }); ?>
</ul></p>
<?js } ?>
<?js if (data.author && author.length) {?>
<p>Author:</p>
<p>
<ul><?js author.forEach(function(a) { ?>
<li><?js= self.resolveAuthorLinks(a) ?></li>
<?js }); ?></ul>
</p>
<?js } ?>
<?js if (data.copyright) {?>
<p>Copyright:</p>
<p><ul class="dummy"><li><?js= copyright ?></li></ul></p>
<?js } ?>
<?js if (data.license) {?>
<p>License:</p>
<p><ul class="dummy"><li><?js= license ?></li></ul></p>
<?js } ?>
<?js if (data.defaultvalue) {?>
<p>Default Value:</p>
<p><ul class="dummy">
<li<?js= defaultObjectClass ?>><?js= data.defaultvalue ?></li>
</ul></p>
<?js } ?>
<?js if (data.meta && self.outputSourceFiles) {?>
<p>Source:</p>
<p><ul class="dummy"><li>
<?js= self.linkto(meta.shortpath) ?>, <?js= self.linkto(meta.shortpath, 'line ' + meta.lineno, null, 'line' + meta.lineno) ?>
</li></ul></p>
<?js } ?>
<?js if (data.tutorials && tutorials.length) {?>
<p>Tutorials:</p>
<p>
<ul><?js tutorials.forEach(function(t) { ?>
<li><?js= self.tutoriallink(t) ?></li>
<?js }); ?></ul>
</p>
<?js } ?>
<?js if (data.see && see.length) {?>
<p class="see">See:</p>
<p>
<ul><?js see.forEach(function(s) { ?>
<li><?js= self.linkto(s) ?></li>
<?js }); ?></ul>
</p>
<?js } ?>
<?js if (data.todo && todo.length) {?>
<p>To Do:</p>
<p>
<ul><?js todo.forEach(function(t) { ?>
<li><?js= t ?></li>
<?js }); ?></ul>
</p>
<?js } ?>

View file

@ -0,0 +1,141 @@
<?js
var data = obj;
var self = this;
var defaultObjectClass = '';
// Check if the default value is an object or array; if so, apply code highlighting
if (data.defaultvalue && (data.defaultvaluetype === 'object' || data.defaultvaluetype === 'array')) {
data.defaultvalue = "<pre class=\"prettyprint\"><code>" + data.defaultvalue + "</code></pre>";
defaultObjectClass = ' class="object-value"';
}
?>
<?js
var properties = data.properties;
if (properties && properties.length && properties.forEach && !data.hideconstructor) {
?>
<?js if (data.deprecated) { ?>
<p class="important">Deprecated: <?js
if (data.deprecated === true) { ?>Yes</p><?js }
else { ?><?js= data.deprecated ?></p><?js }
?>
<?js } ?>
<h3 class="propsHeading" id="props">Properties</h3>
<?js= this.partial('properties.tmpl', data) ?>
<?js } ?>
<?js if (data.version) {?>
<p>Version:</p>
<p><ul class="dummy"><li><?js= version ?></li></ul></p>
<?js } ?>
<?js if (data.since) {?>
<p>Since:</p>
<p><ul class="dummy"><li><?js= since ?></li></ul></p>
<?js } ?>
<?js if (data.inherited && data.inherits && !data.overrides) { ?>
<p>Inherited From:</p>
<p><ul class="dummy"><li>
<?js= this.linkto(data.inherits, this.htmlsafe(data.inherits)) ?>
</li></ul></p>
<?js } ?>
<?js if (data.overrides) { ?>
<p>Overrides:</p>
<p><ul class="dummy"><li>
<?js= this.linkto(data.overrides, this.htmlsafe(data.overrides)) ?>
</li></ul></p>
<?js } ?>
<?js if (data.implementations && data.implementations.length) { ?>
<p>Implementations:</p>
<p><ul>
<?js data.implementations.forEach(function(impl) { ?>
<li><?js= self.linkto(impl, self.htmlsafe(impl)) ?></li>
<?js }); ?>
</ul></p>
<?js } ?>
<?js if (data.implements && data.implements.length) { ?>
<p>Implements:</p>
<p><ul>
<?js data.implements.forEach(function(impl) { ?>
<li><?js= self.linkto(impl, self.htmlsafe(impl)) ?></li>
<?js }); ?>
</ul></p>
<?js } ?>
<?js if (data.mixes && data.mixes.length) { ?>
<p>Mixes In:</p>
<p><ul>
<?js data.mixes.forEach(function(a) { ?>
<li><?js= self.linkto(a, a) ?></li>
<?js }); ?>
</ul></p>
<?js } ?>
<?js if (data.author && author.length) {?>
<p>Author:</p>
<p>
<ul><?js author.forEach(function(a) { ?>
<li><?js= self.resolveAuthorLinks(a) ?></li>
<?js }); ?></ul>
</p>
<?js } ?>
<?js if (data.copyright) {?>
<p>Copyright:</p>
<p><ul class="dummy"><li><?js= copyright ?></li></ul></p>
<?js } ?>
<?js if (data.license) {?>
<p>License:</p>
<p><ul class="dummy"><li><?js= license ?></li></ul></p>
<?js } ?>
<?js if (data.defaultvalue) {?>
<p>Default Value:</p>
<p><ul class="dummy">
<li<?js= defaultObjectClass ?>><?js= data.defaultvalue ?></li>
</ul></p>
<?js } ?>
<?js if (data.meta && self.outputSourceFiles) {?>
<p>Source:</p>
<p><ul class="dummy"><li>
<?js= self.linkto(meta.shortpath) ?>, <?js= self.linkto(meta.shortpath, 'line ' + meta.lineno, null, 'line' + meta.lineno) ?>
</li></ul></p>
<?js } ?>
<?js if (data.tutorials && tutorials.length) {?>
<p>Tutorials:</p>
<p>
<ul><?js tutorials.forEach(function(t) { ?>
<li><?js= self.tutoriallink(t) ?></li>
<?js }); ?></ul>
</p>
<?js } ?>
<?js if (data.see && see.length) {?>
<p class="see">See:</p>
<p>
<ul><?js see.forEach(function(s) { ?>
<li><?js= self.linkto(s) ?></li>
<?js }); ?></ul>
</p>
<?js } ?>
<?js if (data.todo && todo.length) {?>
<p>To Do:</p>
<p>
<ul><?js todo.forEach(function(t) { ?>
<li><?js= t ?></li>
<?js }); ?></ul>
</p>
<?js } ?>

View file

@ -0,0 +1,13 @@
<?js
var data = obj;
var self = this;
data.forEach(function(example) {
if (example.caption) {
?>
<p class="code-caption"><?js= example.caption ?></p>
<?js } ?>
<pre class="prettyprint"><code><?js= self.htmlsafe(example.code) ?></code></pre>
<?js
});
?>

View file

@ -0,0 +1,32 @@
<?js
var data = obj;
?>
<?js if (data.description && data.type && data.type.names) { ?>
<dl>
<dt>
<div class="param-desc">
<?js= data.description ?>
</div>
</dt>
<dd></dd>
<dt>
<dl class="param-type">
<dt>
Type
</dt>
<dd>
<?js= this.partial('type.tmpl', data.type.names) ?>
</dd>
</dl>
</dt>
<dd></dd>
</dl>
<?js } else { ?>
<div class="param-desc">
<?js if (data.description) { ?>
<?js= data.description ?>
<?js } else if (data.type && data.type.names) { ?>
<?js= this.partial('type.tmpl', data.type.names) ?>
<?js } ?>
</div>
<?js } ?>

View file

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="en">
<head>
<?js if (!env.conf.docdash) { env.conf.docdash = {};} ?>
<meta charset="utf-8">
<title><?js= title ?></title>
<script src="scripts/prettify/prettify.js"></script>
<script src="scripts/prettify/lang-css.js"></script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
</head>
<body>
<div class="nav-header">
<p><img src="images/white-logo.png" width="200px" /></p>
<?js if (env.conf.docdash.search) { ?>
<input type="text" class="search-input" id="nav-search" placeholder="Search ..." />
<?js } ?>
</div>
<nav>
<?js= this.nav ?>
</nav>
<div id="main">
<h1 class="page-title"><?js= title ?></h1>
<?js= content ?>
<?js if (env.conf.docdash.disqus) { ?>
<div id="disqus_thread"></div>
<script>
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = '//<?js= env.conf.docdash.disqus ?>.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<?js } ?>
</div>
<br class="clear">
<script>prettyPrint();</script>
<script src="scripts/linenumber.js"></script>
<?js if (env.conf.docdash.search || env.conf.docdash.collapse) { ?>
<script src="scripts/jquery-3.1.1.min.js"></script>
<?js if (env.conf.docdash.search) { ?>
<script src="scripts/search.js"></script>
<?js } ?>
<?js if (env.conf.docdash.collapse) { ?>
<script src="scripts/collapse.js"></script>
<?js } ?>
<?js } ?>
<?js if (env.conf.docdash.scripts && env.conf.docdash.scripts.length) {
for(var i = 0; i < env.conf.docdash.scripts.length; i++) {
if (env.conf.docdash.scripts[i].indexOf(".css") != -1) { ?>
<link type="text/css" rel="stylesheet" href="<?js= env.conf.docdash.scripts[i] ?>">
<?js } else { ?>
<script src="<?js= env.conf.docdash.scripts[i] ?>"></script>
<?js } ?>
<?js } ?>
<?js } ?>
</body>
</html>

View file

@ -0,0 +1,10 @@
<?js
var data = obj;
var self = this;
?>
<?js if (data.readme) { ?>
<section class="readme">
<article><?js= data.readme ?></article>
</section>
<?js } ?>

View file

@ -0,0 +1,41 @@
<?js
var data = obj;
var self = this;
?>
<table>
<thead>
<tr>
<th>
<span id="<?js= id ?>" class="member"><?js= data.attribs + name + (data.signature ? data.signature : '') ?></span><br />
Type: <?js= self.partial('type.tmpl', data.type.names) ?>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<?js if (data.description) { ?>
<p><?js= data.description ?></p>
<?js } else { ?>
<p style="color:red;">&nbsp;</p>
<?js } ?>
<?js= self.partial('details.tmpl', data) ?>
<?js if (data.examples && examples.length) { ?>
<h5>Example<?js= examples.length > 1? 's':'' ?></h5>
<?js= this.partial('examples.tmpl', examples) ?>
<?js } ?>
</td>
</tr>
</tbody>
</table>
<?js if (data.fires && fires.length) { ?>
<h5>Fires:</h5>
<ul><?js fires.forEach(function(f) { ?>
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>

View file

@ -0,0 +1,119 @@
<?js
var data = obj;
var self = this;
?>
<?js if (data.kind !== 'module' && !data.hideconstructor) { ?>
<table>
<thead>
<tr>
<th>
<span id="<?js= id ?>" class="member"><?js= data.attribs + (kind === 'class' ? 'new ' : '') + name + (data.signature || '') ?></span>
<?js if (data.returns && returns.length) { ?><br />
Returns: <span style="font-weight: normal;">
<?js returns.forEach(function(r) { ?>
<?js= self.partial('returns.tmpl', r) ?>
<?js });
} ?></span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<?js if (data.kind !== 'module' && data.description && !data.hideconstructor) { ?>
<p>
<?js= data.description ?>
<?js= this.partial('details.tmpl', data) ?>
</p>
<?js } else { ?>
<p style="color:red;">&nbsp;</p>
<?js } ?>
<?js if (data.exceptions && exceptions.length) { ?>
<h3 class="subHeading">Throws:</h3>
<?js if (exceptions.length > 1) { ?><ul><?js
exceptions.forEach(function(r) { ?>
<li><?js= self.partial('exceptions.tmpl', r) ?></li>
<?js });
?></ul><?js } else {
exceptions.forEach(function(r) { ?>
<p><?js= self.partial('exceptions.tmpl', r) ?></p>
<?js });
} } ?>
<?js if (data.params && params.length && !data.hideconstructor) { ?>
<h3 class="subHeading">Parameters</h3>
<?js= this.partial('params.tmpl', params) ?>
<?js } ?>
<?js if (data.examples && examples.length) { ?>
<h5>Example<?js= examples.length > 1? 's':'' ?></h5>
<?js= this.partial('examples.tmpl', examples) ?>
<?js } ?>
</td>
</tr>
</tbody>
</table>
<?js } ?>
<?js if (data.augments && data.alias && data.alias.indexOf('module:') === 0) { ?>
<h5>Extends:</h5>
<?js= self.partial('augments.tmpl', data) ?>
<?js } ?>
<?js if (kind === 'event' && data.type && data.type.names) {?>
<h5>Type:</h5>
<ul>
<li>
<?js= self.partial('type.tmpl', data.type.names) ?>
</li>
</ul>
<?js } ?>
<?js if (data['this']) { ?>
<h5>This:</h5>
<ul><li><?js= this.linkto(data['this'], data['this']) ?></li></ul>
<?js } ?>
<?js if (data.kind !== 'module' && data.requires && data.requires.length) { ?>
<h5>Requires:</h5>
<ul><?js data.requires.forEach(function(r) { ?>
<li><?js= self.linkto(r) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.fires && fires.length) { ?>
<h5>Fires:</h5>
<ul><?js fires.forEach(function(f) { ?>
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.listens && listens.length) { ?>
<h5>Listens to Events:</h5>
<ul><?js listens.forEach(function(f) { ?>
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.listeners && listeners.length) { ?>
<h5>Listeners of This Event:</h5>
<ul><?js listeners.forEach(function(f) { ?>
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.yields && yields.length) { ?>
<h5>Yields:</h5>
<?js if (yields.length > 1) { ?><ul><?js
yields.forEach(function(r) { ?>
<li><?js= self.partial('returns.tmpl', r) ?></li>
<?js });
?></ul><?js } else {
yields.forEach(function(r) { ?>
<?js= self.partial('returns.tmpl', r) ?>
<?js });
} } ?>

View file

@ -0,0 +1,107 @@
<?js
var data = obj;
var self = this;
?>
<?js if (data.kind !== 'module' && !data.hideconstructor) { ?>
<?js if (data.kind === 'class' && data.classdesc) { ?>
<h2>Constructor</h2>
<?js } ?>
<?js if (data.kind !== 'namespace') { ?>
<tr>
<td><a href="#<?js= id ?>">
<code><?js= (kind === 'class' ? 'new ' : '') + name + (data.signatureHead || '') ?></code></a>
</td>
<td>
<?js if (!data.returns) { ?>
None
<?js } else if (data.returns && returns.length) { ?>
<?js if (returns.length > 1) { ?><ul><?js
returns.forEach(function(r) { ?>
<li><?js= self.partial('returnsSimp.tmpl', r) ?></li>
<?js });
?></ul><?js } else {
returns.forEach(function(r) { ?>
<?js= self.partial('returnsSimp.tmpl', r) ?>
<?js });
} ?>
<?js } ?>
</td>
<td>
<?js if (data.description) { ?>
<?js= description ?>
<?js= this.partial('details.tmpl', data) ?>
<?js } else { ?>
<?js= this.partial('details.tmpl', data) ?>
<?js } ?>
</td>
</tr>
<?js } ?>
<?js } ?>
<?js if (data.augments && data.alias && data.alias.indexOf('module:') === 0) { ?>
<h5>Extends:</h5>
<?js= self.partial('augments.tmpl', data) ?>
<?js } ?>
<?js if (kind === 'event' && data.type && data.type.names) {?>
<h5>Type:</h5>
<ul>
<li>
<?js= self.partial('type.tmpl', data.type.names) ?>
</li>
</ul>
<?js } ?>
<?js if (data['this']) { ?>
<h5>This:</h5>
<ul><li><?js= this.linkto(data['this'], data['this']) ?></li></ul>
<?js } ?>
<?js if (data.kind !== 'module' && data.requires && data.requires.length) { ?>
<h5>Requires:</h5>
<ul><?js data.requires.forEach(function(r) { ?>
<li><?js= self.linkto(r) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.fires && fires.length) { ?>
<h5>Fires:</h5>
<ul><?js fires.forEach(function(f) { ?>
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.listens && listens.length) { ?>
<h5>Listens to Events:</h5>
<ul><?js listens.forEach(function(f) { ?>
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.listeners && listeners.length) { ?>
<h5>Listeners of This Event:</h5>
<ul><?js listeners.forEach(function(f) { ?>
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.yields && yields.length) { ?>
<h5>Yields:</h5>
<?js if (yields.length > 1) { ?><ul><?js
yields.forEach(function(r) { ?>
<li><?js= self.partial('returns.tmpl', r) ?></li>
<?js });
?></ul><?js } else {
yields.forEach(function(r) { ?>
<?js= self.partial('returnsSimp.tmpl', r) ?>
<?js });
} } ?>
<!--
<?js if (data.examples && examples.length) { ?>
<h5>Example<?js= examples.length > 1? 's':'' ?></h5>
<?js= this.partial('examples.tmpl', examples) ?>
<?js } ?>
-->

View file

@ -0,0 +1,67 @@
<?js
var params = obj;
/* sort subparams under their parent params (like opts.classname) */
var parentParam = null;
params.forEach(function(param, i) {
var paramRegExp;
if (!param) {
return;
}
if (parentParam && parentParam.name && param.name) {
try {
paramRegExp = new RegExp('^(?:' + parentParam.name + '(?:\\[\\])*)\\.(.+)$');
}
catch (e) {
// there's probably a typo in the JSDoc comment that resulted in a weird
// parameter name
return;
}
if ( paramRegExp.test(param.name) ) {
param.name = RegExp.$1;
parentParam.subparams = parentParam.subparams || [];
parentParam.subparams.push(param);
params[i] = null;
}
else {
parentParam = param;
}
}
else {
parentParam = param;
}
});
/* determine if we need extra columns, "attributes" and "default" */
params.hasAttributes = false;
params.hasDefault = false;
params.hasName = false;
params.forEach(function(param) {
if (!param) { return; }
if (param.optional || param.nullable || param.variable) {
params.hasAttributes = true;
}
if (param.name) {
params.hasName = true;
}
if (typeof param.defaultvalue !== 'undefined') {
params.hasDefault = true;
}
});
?>
<?js params.forEach(function(param, i, arr) { ?>
<?js if (i === arr.length - 1) { ?>
<?js= param.name ?>
<?js } else { ?>
<span><?js= param.name ?>, </span>
<?js } ?>
<?js }); ?>

View file

@ -0,0 +1,115 @@
<?js
var params = obj;
/* sort subparams under their parent params (like opts.classname) */
var parentParam = null;
params.forEach(function(param, i) {
var paramRegExp;
if (!param) {
return;
}
if (parentParam && parentParam.name && param.name) {
try {
paramRegExp = new RegExp('^(?:' + parentParam.name + '(?:\\[\\])*)\\.(.+)$');
}
catch (e) {
// there's probably a typo in the JSDoc comment that resulted in a weird
// parameter name
return;
}
if ( paramRegExp.test(param.name) ) {
param.name = RegExp.$1;
parentParam.subparams = parentParam.subparams || [];
parentParam.subparams.push(param);
params[i] = null;
}
else {
parentParam = param;
}
}
else {
parentParam = param;
}
});
/* determine if we need extra columns, "attributes" and "default" */
params.hasAttributes = false;
params.hasDefault = false;
params.hasName = false;
params.forEach(function(param) {
if (!param) { return; }
if (param.optional || param.nullable || param.variable) {
params.hasAttributes = true;
}
if (param.name) {
params.hasName = true;
}
if (typeof param.defaultvalue !== 'undefined') {
params.hasDefault = true;
}
});
?>
<table class="params">
<thead>
<tr>
<?js if (params.hasName) {?>
<th>Name</th>
<?js } ?>
<th>Type</th>
<?js if (params.hasAttributes) {?>
<th>Attributes</th>
<?js } ?>
<?js if (params.hasDefault) {?>
<th>Default</th>
<?js } ?>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<?js
var self = this;
params.forEach(function(param) {
if (!param) { return; }
?>
<tr>
<?js if (params.hasName) {?>
<td class="name"><code><?js= param.name ?></code></td>
<?js } ?>
<td class="type">
<?js if (param.type && param.type.names) {?>
<?js= self.partial('type.tmpl', param.type.names) ?>
<?js } ?>
</td>
<?js if (params.hasDefault) {?>
<td class="default">
<?js if (typeof param.defaultvalue !== 'undefined') { ?>
Default Value: <?js= self.htmlsafe(param.defaultvalue) ?>
<?js } ?>
</td>
<?js } ?>
<td class="description last"><?js= param.description ?><?js if (param.subparams) { ?>
<h6>Properties</h6>
<?js= self.partial('params.tmpl', param.subparams) ?>
<?js } ?></td>
</tr>
<?js }); ?>
</tbody>
</table>

View file

@ -0,0 +1,103 @@
<?js
var data = obj;
var props = data.subprops || data.properties;
/* sort subprops under their parent props (like opts.classname) */
var parentProp = null;
props.forEach(function(prop, i) {
if (!prop) { return; }
if ( parentProp && prop.name && prop.name.indexOf(parentProp.name + '.') === 0 ) {
prop.name = prop.name.substr(parentProp.name.length+1);
parentProp.subprops = parentProp.subprops || [];
parentProp.subprops.push(prop);
props[i] = null;
}
else {
parentProp = prop;
}
});
/* determine if we need extra columns, "attributes" and "default" */
props.hasAttributes = false;
props.hasDefault = false;
props.hasName = false;
props.forEach(function(prop) {
if (!prop) { return; }
if (prop.optional || prop.nullable) {
props.hasAttributes = true;
}
if (prop.name) {
props.hasName = true;
}
if (typeof prop.defaultvalue !== 'undefined' && !data.isEnum) {
props.hasDefault = true;
}
});
?>
<table class="props">
<thead>
<tr>
<?js if (props.hasName) {?>
<th class="first">Name</th>
<?js } ?>
<th class="type">Type</th>
<?js if (props.hasAttributes) {?>
<th>Attributes</th>
<?js } ?>
<th class="last">Summary</th>
</tr>
</thead>
<tbody>
<?js
var self = this;
props.forEach(function(prop) {
if (!prop) { return; }
?>
<tr>
<?js if (props.hasName) {?>
<td><span class="signature"><?js= prop.name ?></span></td>
<?js } ?>
<td class="type">
<?js if (prop.type && prop.type.names) {?>
<?js= self.partial('type.tmpl', prop.type.names) ?>
<?js } ?>
</td>
<?js if (props.hasAttributes) {?>
<td class="attributes">
<?js if (prop.optional) { ?>
&lt;optional><br>
<?js } ?>
<?js if (prop.nullable) { ?>
&lt;nullable><br>
<?js } ?>
</td>
<?js } ?>
<td class="description last">
<?js= prop.description ?>
<?js if (props.hasDefault) {?>
<?js if (typeof prop.defaultvalue !== 'undefined') { ?>
<p><b>Default Value:</b> <?js= self.htmlsafe(prop.defaultvalue) ?> </p>
<?js } ?>
<?js } ?>
<?js if (prop.subprops) { ?>
<h6>Properties</h6><?js= self.partial('properties.tmpl', prop) ?>
<?js } ?>
</td>
</tr>
<?js }); ?>
</tbody>
</table>

View file

@ -0,0 +1,8 @@
<?js
var data = obj || {};
if (data.description) {
?>
<?js= description ?>
<?js } else { ?>
<?js= this.partial('type.tmpl', data.type.names) ?>
<?js } ?>

View file

@ -0,0 +1,6 @@
<?js
var data = obj || {}; ?>
<?js if (data.type && data.type.names) {?>
<?js= this.partial('type.tmpl', data.type.names) ?>
<?js } ?>

View file

@ -0,0 +1,123 @@
<?js
var data = obj;
var self = this;
?>
<?js if (data.kind !== 'module' && !data.hideconstructor) { ?>
<table>
<thead>
<tr>
<th>
<span id="<?js= id ?>" class="member"><?js= name ?>(
<?js if (data.params) { ?>
<?js= self.partial('paramList.tmpl', params) ?>
<?js } ?>
)</span>
<?js if (data.returns && returns.length) { ?><br />
Returns: <span style="font-weight: normal;">
<?js returns.forEach(function(r) { ?>
<?js= self.partial('returns.tmpl', r) ?>
<?js });
} ?></span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<?js if (data.kind !== 'module' && data.description && !data.hideconstructor) { ?>
<p>
<?js= data.description ?>
<?js= this.partial('details.tmpl', data) ?>
</p>
<?js } else { ?>
<p style="color:red;">&nbsp;</p>
<?js } ?>
<?js if (data.exceptions && exceptions.length) { ?>
<h3 class="subHeading">Throws:</h3>
<?js if (exceptions.length > 1) { ?><ul><?js
exceptions.forEach(function(r) { ?>
<li><?js= self.partial('exceptions.tmpl', r) ?></li>
<?js });
?></ul><?js } else {
exceptions.forEach(function(r) { ?>
<p><?js= self.partial('exceptions.tmpl', r) ?></p>
<?js });
} } ?>
<?js if (data.params && params.length && !data.hideconstructor) { ?>
<h3 class="subHeading">Parameters</h3>
<?js= this.partial('params.tmpl', params) ?>
<?js } ?>
<?js if (data.examples && examples.length) { ?>
<h5>Example<?js= examples.length > 1? 's':'' ?></h5>
<?js= this.partial('examples.tmpl', examples) ?>
<?js } ?>
</td>
</tr>
</tbody>
</table>
<?js } ?>
<?js if (data.augments && data.alias && data.alias.indexOf('module:') === 0) { ?>
<h5>Extends:</h5>
<?js= self.partial('augments.tmpl', data) ?>
<?js } ?>
<?js if (kind === 'event' && data.type && data.type.names) {?>
<h5>Type:</h5>
<ul>
<li>
<?js= self.partial('type.tmpl', data.type.names) ?>
</li>
</ul>
<?js } ?>
<?js if (data['this']) { ?>
<h5>This:</h5>
<ul><li><?js= this.linkto(data['this'], data['this']) ?></li></ul>
<?js } ?>
<?js if (data.kind !== 'module' && data.requires && data.requires.length) { ?>
<h5>Requires:</h5>
<ul><?js data.requires.forEach(function(r) { ?>
<li><?js= self.linkto(r) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.fires && fires.length) { ?>
<h5>Fires:</h5>
<ul><?js fires.forEach(function(f) { ?>
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.listens && listens.length) { ?>
<h5>Listens to Events:</h5>
<ul><?js listens.forEach(function(f) { ?>
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.listeners && listeners.length) { ?>
<h5>Listeners of This Event:</h5>
<ul><?js listeners.forEach(function(f) { ?>
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.yields && yields.length) { ?>
<h5>Yields:</h5>
<?js if (yields.length > 1) { ?><ul><?js
yields.forEach(function(r) { ?>
<li><?js= self.partial('returns.tmpl', r) ?></li>
<?js });
?></ul><?js } else {
yields.forEach(function(r) { ?>
<?js= self.partial('returns.tmpl', r) ?>
<?js });
} } ?>

View file

@ -0,0 +1,92 @@
<?js
var data = obj;
var self = this;
?>
<?js if (data.kind !== 'module' && !data.hideconstructor) { ?>
<?js if (data.kind === 'class' && data.classdesc) { ?>
<h2>Constructor</h2>
<?js } ?>
<?js if (data.kind !== 'namespace') { ?>
<tr>
<td><a href="#<?js= id ?>">
<code><?js= (kind === 'class' ? 'new ' : '') + name + (data.signatureHead || '') ?></code></a>
</td>
<td>
<?js if (data.summary) { ?>
<?js= summary ?>
<?js= this.partial('details.tmpl', data) ?>
<?js } else { ?>
<?js= this.partial('details.tmpl', data) ?>
<?js } ?>
</td>
</tr>
<?js } ?>
<?js } ?>
<?js if (data.augments && data.alias && data.alias.indexOf('module:') === 0) { ?>
<h5>Extends:</h5>
<?js= self.partial('augments.tmpl', data) ?>
<?js } ?>
<?js if (kind === 'event' && data.type && data.type.names) {?>
<h5>Type:</h5>
<ul>
<li>
<?js= self.partial('type.tmpl', data.type.names) ?>
</li>
</ul>
<?js } ?>
<?js if (data['this']) { ?>
<h5>This:</h5>
<ul><li><?js= this.linkto(data['this'], data['this']) ?></li></ul>
<?js } ?>
<?js if (data.kind !== 'module' && data.requires && data.requires.length) { ?>
<h5>Requires:</h5>
<ul><?js data.requires.forEach(function(r) { ?>
<li><?js= self.linkto(r) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.fires && fires.length) { ?>
<h5>Fires:</h5>
<ul><?js fires.forEach(function(f) { ?>
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.listens && listens.length) { ?>
<h5>Listens to Events:</h5>
<ul><?js listens.forEach(function(f) { ?>
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.listeners && listeners.length) { ?>
<h5>Listeners of This Event:</h5>
<ul><?js listeners.forEach(function(f) { ?>
<li><?js= self.linkto(f) ?></li>
<?js }); ?></ul>
<?js } ?>
<?js if (data.yields && yields.length) { ?>
<h5>Yields:</h5>
<?js if (yields.length > 1) { ?><ul><?js
yields.forEach(function(r) { ?>
<li><?js= self.partial('returns.tmpl', r) ?></li>
<?js });
?></ul><?js } else {
yields.forEach(function(r) { ?>
<?js= self.partial('returnsSimp.tmpl', r) ?>
<?js });
} } ?>
<!--
<?js if (data.examples && examples.length) { ?>
<h5>Example<?js= examples.length > 1? 's':'' ?></h5>
<?js= this.partial('examples.tmpl', examples) ?>
<?js } ?>
-->

View file

@ -0,0 +1,8 @@
<?js
var data = obj;
?>
<section>
<article>
<pre class="prettyprint source linenums"><code><?js= data.code ?></code></pre>
</article>
</section>

View file

@ -0,0 +1,19 @@
<section>
<header>
<?js if (children.length > 0) { ?>
<ul><?js
var self = this;
children.forEach(function(t) { ?>
<li><?js= self.tutoriallink(t.name) ?></li>
<?js }); ?></ul>
<?js } ?>
<h2><?js= header ?></h2>
</header>
<article>
<?js= content ?>
</article>
</section>

View file

@ -0,0 +1,7 @@
<?js
var data = obj;
var self = this;
data.forEach(function(name, i) { ?>
<?js= self.linkto(name, self.htmlsafe(name)) ?>
<?js if (i < data.length-1) { ?>|<?js } ?>
<?js }); ?>

View file

@ -107,9 +107,6 @@ exports.handlers = {
if (e.doclet.hifiClientEntity) {
rows.push("Client Entity Scripts");
}
if (e.doclet.hifiAvatar) {
rows.push("Avatar Scripts");
}
if (e.doclet.hifiServerEntity) {
rows.push("Server Entity Scripts");
}
@ -117,15 +114,30 @@ exports.handlers = {
rows.push("Assignment Client Scripts");
}
// Append an Available In: table at the end of the namespace description.
// Append an Available In: sentence at the beginning of the namespace description.
if (rows.length > 0) {
var table = "<table><tr><th>Available in:</th><td>" + rows.join("</td><td>") + "</td></tr></table><br>";
e.doclet.description = table + (e.doclet.description ? e.doclet.description : "");
}
var availableIn = "<p class='availableIn'><b>Supported Script Types:</b> " + rows.join(" &bull; ") + "</p>";
e.doclet.description = (e.doclet.description ? e.doclet.description : "") + availableIn;
}
}
}
};
// Functions for adding @signal custom tag
/** @private */
function setDocletKindToTitle(doclet, tag) {
doclet.addTag( 'kind', tag.title );
}
function setDocletNameToValue(doclet, tag) {
if (tag.value && tag.value.description) { // as in a long tag
doclet.addTag('name', tag.value.description);
} else if (tag.text) { // or a short tag
doclet.addTag('name', tag.text);
}
}
// Define custom hifi tags here
exports.defineTags = function (dictionary) {
@ -143,14 +155,6 @@ exports.defineTags = function (dictionary) {
}
});
// @hifi-avatar-script
dictionary.defineTag("hifi-avatar", {
onTagged: function (doclet, tag) {
doclet.hifiAvatar = true;
}
});
// @hifi-client-entity
dictionary.defineTag("hifi-client-entity", {
onTagged: function (doclet, tag) {
@ -164,4 +168,14 @@ exports.defineTags = function (dictionary) {
doclet.hifiServerEntity = true;
}
});
// @signal
dictionary.defineTag("signal", {
mustHaveValue: true,
onTagged: function(doclet, tag) {
setDocletKindToTitle(doclet, tag);
setDocletNameToValue(doclet, tag);
}
});
};

View file

@ -47,24 +47,30 @@ These steps assume the hifi repository has been cloned to `~/hifi`.
### Windows
1. (First time) download and install Python 3 from https://hifi-qa.s3.amazonaws.com/nitpick/Windows/python-3.7.0-amd64.exe (also located at https://www.python.org/downloads/)
1. Click the "add python to path" checkbox on the python installer
1. After installation - add the path to python.exe to the Windows PATH environment variable.
1. After installation:
1. Open a new terminal
1. Enter `python` and hit enter
1. Verify that python is available (the prompt will change to `>>>`)
1. Type `exit()` and hit enter to close python
1. Install requests (a python library to download files from URLs)
`pip3 install requests`
1. (First time) download and install AWS CLI from https://hifi-qa.s3.amazonaws.com/nitpick/Windows/AWSCLI64PY3.msi (also available at https://aws.amazon.com/cli/
1. Open a new command prompt and run
`aws configure`
1. Enter the AWS account number
1. Enter the secret key
1. Leave region name and ouput format as default [None]
1. Install the latest release of Boto3 via pip:
1. Install the latest release of Boto3 via pip (from a terminal):
`pip install boto3`
1. (First time) Download adb (Android Debug Bridge) from *https://dl.google.com/android/repository/platform-tools-latest-windows.zip*
1. Copy the downloaded file to (for example) **C:\adb** and extract in place.
Verify you see *adb.exe* in **C:\adb\platform-tools\\**.
1. After installation - add the path to adb.exe to the Windows PATH environment variable (note that it is in *adb\platform-tools*).
1. `nitpick` is included in the High Fidelity installer but can also be downloaded from:
1. `nitpick` is included in the High Fidelity installer but can also be downloaded from (change X.X.X to correct version):
[here](<https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-vX.X.X.dmg>).*
### Mac
1. (first time) Install brew
1. (First time) Install brew
In a terminal:
`/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`
Note that you will need to press RETURN again, and will then be asked for your password.
@ -76,11 +82,13 @@ These steps assume the hifi repository has been cloned to `~/hifi`.
`open "/Applications/Python 3.7/Install Certificates.command"`.
This is needed because the Mac Python supplied no longer links with the deprecated Apple-supplied system OpenSSL libraries but rather supplies a private copy of OpenSSL 1.0.2 which does not automatically access the system default root certificates.
1. Verify that `/usr/local/bin/python3` exists.
1. (First time - AWS interface) Install pip with the script provided by the Python Packaging Authority:
In a terminal:
`curl -O https://bootstrap.pypa.io/get-pip.py`
In a terminal:
`python3 get-pip.py --user`
1. Install requests (a python library to download files from URLs)
`pip3 install requests`
1. (First time - AWS interface) Install pip with the script provided by the Python Packaging Authority:
1. Use pip to install the AWS CLI.
`pip3 install awscli --upgrade --user`
This will install aws in your user. For user XXX, aws will be located in ~/Library/Python/3.7/bin
@ -92,6 +100,16 @@ This is needed because the Mac Python supplied no longer links with the deprecat
1. Install the latest release of Boto3 via pip: pip3 install boto3
1. (First time)Install adb (the Android Debug Bridge) - in a terminal:
`brew cask install android-platform-tools`
1. (First time) Set terminal privileges
1. Click on Apple icon (top left)
1. Select System Preferences...
1. Select Security & Privacy
1. Select Accessibility
1. Click on "Click the lock to make changes" and enter passsword if requested
1. Set Checkbox near *Terminal* to checked.
1. Click on "Click the lock to prevent furthur changes"
1. Close window
1. `nitpick` is included in the High Fidelity installer but can also be downloaded from:
[here](<https://hifi-qa.s3.amazonaws.com/nitpick/Mac/nitpick-installer-vX.X.X.dmg>).*
# Usage

View file

@ -480,7 +480,7 @@ void AWSInterface::updateAWS() {
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
"Could not create 'addTestCases.py'");
"Could not create 'updateAWS.py'");
exit(-1);
}

View file

@ -16,12 +16,13 @@
QString AdbInterface::getAdbCommand() {
#ifdef Q_OS_WIN
if (_adbCommand.isNull()) {
QString adbPath = PathUtils::getPathToExecutable("adb.exe");
QString adbExe{ "adb.exe" };
QString adbPath = PathUtils::getPathToExecutable(adbExe);
if (!adbPath.isNull()) {
_adbCommand = adbPath + _adbExe;
_adbCommand = adbExe;
} else {
QMessageBox::critical(0, "python.exe not found",
"Please verify that pyton.exe is in the PATH");
QMessageBox::critical(0, "adb.exe not found",
"Please verify that adb.exe is in the PATH");
exit(-1);
}
}

View file

@ -17,12 +17,6 @@ public:
QString getAdbCommand();
private:
#ifdef Q_OS_WIN
const QString _adbExe{ "adb.exe" };
#else
// Both Mac and Linux use "python"
const QString _adbExe{ "adb" };
#endif
QString _adbCommand;
};

View file

@ -8,32 +8,65 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Downloader.h"
#include "PythonInterface.h"
#include <QtWidgets/QMessageBox>
#include <QFile>
#include <QMessageBox>
#include <QProcess>
#include <QThread>
#include <QTextStream>
Downloader::Downloader(QUrl fileURL, QObject *parent) : QObject(parent) {
_networkAccessManager.get(QNetworkRequest(fileURL));
connect(
&_networkAccessManager, SIGNAL (finished(QNetworkReply*)),
this, SLOT (fileDownloaded(QNetworkReply*))
);
Downloader::Downloader() {
PythonInterface* pythonInterface = new PythonInterface();
_pythonCommand = pythonInterface->getPythonCommand();
}
void Downloader::fileDownloaded(QNetworkReply* reply) {
QNetworkReply::NetworkError error = reply->error();
if (error != QNetworkReply::NetworkError::NoError) {
QMessageBox::information(0, "Test Aborted", "Failed to download file: " + reply->errorString());
void Downloader::downloadFiles(const QStringList& URLs, const QString& directoryName, const QStringList& filenames, void *caller) {
if (URLs.size() <= 0) {
return;
}
_downloadedData = reply->readAll();
QString filename = directoryName + "/downloadFiles.py";
if (QFile::exists(filename)) {
QFile::remove(filename);
}
QFile file(filename);
//emit a signal
reply->deleteLater();
emit downloaded();
}
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
"Could not create 'downloadFiles.py'");
exit(-1);
}
QByteArray Downloader::downloadedData() const {
return _downloadedData;
QTextStream stream(&file);
stream << "import requests\n";
for (int i = 0; i < URLs.size(); ++i) {
stream << "\nurl = '" + URLs[i] + "'\n";
stream << "r = requests.get(url)\n";
stream << "open('" + directoryName + '/' + filenames [i] + "', 'wb').write(r.content)\n";
}
file.close();
#ifdef Q_OS_WIN
QProcess* process = new QProcess();
connect(process, &QProcess::started, this, [=]() { _busyWindow.exec(); });
connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
connect(process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this,
[=](int exitCode, QProcess::ExitStatus exitStatus) { _busyWindow.hide(); });
QStringList parameters = QStringList() << filename;
process->start(_pythonCommand, parameters);
#elif defined Q_OS_MAC
QProcess* process = new QProcess();
QStringList parameters = QStringList() << "-c" << _pythonCommand + " " + filename;
process->start("sh", parameters);
// Wait for the last file to download
while (!QFile::exists(directoryName + '/' + filenames[filenames.length() - 1])) {
QThread::msleep(200);
}
#endif
}

View file

@ -11,38 +11,19 @@
#ifndef hifi_downloader_h
#define hifi_downloader_h
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QDateTime>
#include <QFile>
#include <QFileInfo>
#include <QDebug>
#include "BusyWindow.h"
#include <QObject>
#include <QByteArray>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
class Downloader : public QObject {
Q_OBJECT
public:
explicit Downloader(QUrl fileURL, QObject *parent = 0);
Downloader();
QByteArray downloadedData() const;
signals:
void downloaded();
private slots:
void fileDownloaded(QNetworkReply* pReply);
void downloadFiles(const QStringList& URLs, const QString& directoryName, const QStringList& filenames, void *caller);
private:
QNetworkAccessManager _networkAccessManager;
QByteArray _downloadedData;
QString _pythonCommand;
BusyWindow _busyWindow;
};
#endif // hifi_downloader_h

View file

@ -24,8 +24,6 @@ Nitpick::Nitpick(QWidget* parent) : QMainWindow(parent) {
_ui.progressBar->setVisible(false);
_ui.tabWidget->setCurrentIndex(0);
_signalMapper = new QSignalMapper();
connect(_ui.actionClose, &QAction::triggered, this, &Nitpick::on_closePushbutton_clicked);
connect(_ui.actionAbout, &QAction::triggered, this, &Nitpick::about);
connect(_ui.actionContent, &QAction::triggered, this, &Nitpick::content);
@ -40,7 +38,7 @@ Nitpick::Nitpick(QWidget* parent) : QMainWindow(parent) {
_ui.plainTextEdit->setReadOnly(true);
setWindowTitle("Nitpick - v3.0.1");
setWindowTitle("Nitpick - v3.1.1");
clientProfiles << "VR-High" << "Desktop-High" << "Desktop-Low" << "Mobile-Touch" << "VR-Standalone";
_ui.clientProfileComboBox->insertItems(0, clientProfiles);
@ -48,10 +46,8 @@ Nitpick::Nitpick(QWidget* parent) : QMainWindow(parent) {
}
Nitpick::~Nitpick() {
delete _signalMapper;
if (_test) {
delete _test;
if (_testCreator) {
delete _testCreator;
}
if (_testRunnerDesktop) {
@ -64,10 +60,10 @@ Nitpick::~Nitpick() {
}
void Nitpick::setup() {
if (_test) {
delete _test;
if (_testCreator) {
delete _testCreator;
}
_test = new Test(_ui.progressBar, _ui.checkBoxInteractiveMode);
_testCreator = new TestCreator(_ui.progressBar, _ui.checkBoxInteractiveMode);
std::vector<QCheckBox*> dayCheckboxes;
dayCheckboxes.emplace_back(_ui.mondayCheckBox);
@ -99,9 +95,12 @@ void Nitpick::setup() {
timeEditCheckboxes,
timeEdits,
_ui.workingFolderRunOnDesktopLabel,
_ui.checkBoxServerless,
_ui.checkBoxServerless,
_ui.usePreviousInstallationOnDesktopCheckBox,
_ui.runLatestOnDesktopCheckBox,
_ui.urlOnDesktopLineEdit,
_ui.runFullSuiteOnDesktopCheckBox,
_ui.scriptURLOnDesktopLineEdit,
_ui.runNowPushbutton,
_ui.statusLabelOnDesktop
);
@ -118,8 +117,11 @@ void Nitpick::setup() {
_ui.downloadAPKPushbutton,
_ui.installAPKPushbutton,
_ui.runInterfacePushbutton,
_ui.usePreviousInstallationOnMobileCheckBox,
_ui.runLatestOnMobileCheckBox,
_ui.urlOnMobileLineEdit,
_ui.runFullSuiteOnMobileCheckBox,
_ui.scriptURLOnMobileLineEdit,
_ui.statusLabelOnMobile
);
}
@ -130,7 +132,7 @@ void Nitpick::startTestsEvaluation(const bool isRunningFromCommandLine,
const QString& branch,
const QString& user
) {
_test->startTestsEvaluation(isRunningFromCommandLine, isRunningInAutomaticTestRun, snapshotDirectory, branch, user);
_testCreator->startTestsEvaluation(isRunningFromCommandLine, isRunningInAutomaticTestRun, snapshotDirectory, branch, user);
}
void Nitpick::on_tabWidget_currentChanged(int index) {
@ -149,43 +151,43 @@ void Nitpick::on_tabWidget_currentChanged(int index) {
}
void Nitpick::on_createRecursiveScriptPushbutton_clicked() {
_test->createRecursiveScript();
_testCreator->createRecursiveScript();
}
void Nitpick::on_createAllRecursiveScriptsPushbutton_clicked() {
_test->createAllRecursiveScripts();
_testCreator->createAllRecursiveScripts();
}
void Nitpick::on_createTestsPushbutton_clicked() {
_test->createTests(_ui.clientProfileComboBox->currentText());
_testCreator->createTests(_ui.clientProfileComboBox->currentText());
}
void Nitpick::on_createMDFilePushbutton_clicked() {
_test->createMDFile();
_testCreator->createMDFile();
}
void Nitpick::on_createAllMDFilesPushbutton_clicked() {
_test->createAllMDFiles();
_testCreator->createAllMDFiles();
}
void Nitpick::on_createTestAutoScriptPushbutton_clicked() {
_test->createTestAutoScript();
_testCreator->createTestAutoScript();
}
void Nitpick::on_createAllTestAutoScriptsPushbutton_clicked() {
_test->createAllTestAutoScripts();
_testCreator->createAllTestAutoScripts();
}
void Nitpick::on_createTestsOutlinePushbutton_clicked() {
_test->createTestsOutline();
_testCreator->createTestsOutline();
}
void Nitpick::on_createTestRailTestCasesPushbutton_clicked() {
_test->createTestRailTestCases();
_testCreator->createTestRailTestCases();
}
void Nitpick::on_createTestRailRunButton_clicked() {
_test->createTestRailRun();
_testCreator->createTestRailRun();
}
void Nitpick::on_setWorkingFolderRunOnDesktopPushbutton_clicked() {
@ -202,16 +204,25 @@ void Nitpick::on_runNowPushbutton_clicked() {
_testRunnerDesktop->run();
}
void Nitpick::on_usePreviousInstallationOnDesktopCheckBox_clicked() {
_ui.runLatestOnDesktopCheckBox->setEnabled(!_ui.usePreviousInstallationOnDesktopCheckBox->isChecked());
_ui.urlOnDesktopLineEdit->setEnabled(!_ui.usePreviousInstallationOnDesktopCheckBox->isChecked() && !_ui.runLatestOnDesktopCheckBox->isChecked());
}
void Nitpick::on_runLatestOnDesktopCheckBox_clicked() {
_ui.urlOnDesktopLineEdit->setEnabled(!_ui.runLatestOnDesktopCheckBox->isChecked());
}
void Nitpick::on_runFullSuiteOnDesktopCheckBox_clicked() {
_ui.scriptURLOnDesktopLineEdit->setEnabled(!_ui.runFullSuiteOnDesktopCheckBox->isChecked());
}
void Nitpick::automaticTestRunEvaluationComplete(QString zippedFolderName, int numberOfFailures) {
_testRunnerDesktop->automaticTestRunEvaluationComplete(zippedFolderName, numberOfFailures);
}
void Nitpick::on_updateTestRailRunResultsPushbutton_clicked() {
_test->updateTestRailRunResult();
_testCreator->updateTestRailRunResult();
}
// To toggle between show and hide
@ -239,7 +250,7 @@ void Nitpick::on_showTaskbarPushbutton_clicked() {
}
void Nitpick::on_evaluateTestsPushbutton_clicked() {
_test->startTestsEvaluation(false, false);
_testCreator->startTestsEvaluation(false, false);
}
void Nitpick::on_closePushbutton_clicked() {
@ -247,80 +258,15 @@ void Nitpick::on_closePushbutton_clicked() {
}
void Nitpick::on_createPythonScriptRadioButton_clicked() {
_test->setTestRailCreateMode(PYTHON);
_testCreator->setTestRailCreateMode(PYTHON);
}
void Nitpick::on_createXMLScriptRadioButton_clicked() {
_test->setTestRailCreateMode(XML);
_testCreator->setTestRailCreateMode(XML);
}
void Nitpick::on_createWebPagePushbutton_clicked() {
_test->createWebPage(_ui.updateAWSCheckBox, _ui.diffImageRadioButton, _ui.ssimImageRadioButton, _ui.awsURLLineEdit);
}
void Nitpick::downloadFile(const QUrl& url) {
_downloaders.emplace_back(new Downloader(url, this));
connect(_downloaders[_index], SIGNAL(downloaded()), _signalMapper, SLOT(map()));
_signalMapper->setMapping(_downloaders[_index], _index);
++_index;
}
void Nitpick::downloadFiles(const QStringList& URLs, const QString& directoryName, const QStringList& filenames, void *caller) {
connect(_signalMapper, SIGNAL(mapped(int)), this, SLOT(saveFile(int)));
_directoryName = directoryName;
_filenames = filenames;
_caller = caller;
_numberOfFilesToDownload = URLs.size();
_numberOfFilesDownloaded = 0;
_index = 0;
_ui.progressBar->setMinimum(0);
_ui.progressBar->setMaximum(_numberOfFilesToDownload - 1);
_ui.progressBar->setValue(0);
_ui.progressBar->setVisible(true);
foreach (auto downloader, _downloaders) {
delete downloader;
}
_downloaders.clear();
for (int i = 0; i < _numberOfFilesToDownload; ++i) {
downloadFile(URLs[i]);
}
}
void Nitpick::saveFile(int index) {
try {
QFile file(_directoryName + "/" + _filenames[index]);
file.open(QIODevice::WriteOnly);
file.write(_downloaders[index]->downloadedData());
file.close();
} catch (...) {
QMessageBox::information(0, "Test Aborted", "Failed to save file: " + _filenames[index]);
_ui.progressBar->setVisible(false);
return;
}
++_numberOfFilesDownloaded;
if (_numberOfFilesDownloaded == _numberOfFilesToDownload) {
disconnect(_signalMapper, SIGNAL(mapped(int)), this, SLOT(saveFile(int)));
if (_caller == _test) {
_test->finishTestsEvaluation();
} else if (_caller == _testRunnerDesktop) {
_testRunnerDesktop->downloadComplete();
} else if (_caller == _testRunnerMobile) {
_testRunnerMobile->downloadComplete();
}
_ui.progressBar->setVisible(false);
} else {
_ui.progressBar->setValue(_numberOfFilesDownloaded);
}
_testCreator->createWebPage(_ui.updateAWSCheckBox, _ui.diffImageRadioButton, _ui.ssimImageRadioButton, _ui.awsURLLineEdit);
}
void Nitpick::about() {
@ -360,10 +306,19 @@ void Nitpick::on_connectDevicePushbutton_clicked() {
_testRunnerMobile->connectDevice();
}
void Nitpick::on_usePreviousInstallationOnMobileCheckBox_clicked() {
_ui.runLatestOnMobileCheckBox->setEnabled(!_ui.usePreviousInstallationOnMobileCheckBox->isChecked());
_ui.urlOnMobileLineEdit->setEnabled(!_ui.usePreviousInstallationOnMobileCheckBox->isChecked() && !_ui.runLatestOnMobileCheckBox->isChecked());
}
void Nitpick::on_runLatestOnMobileCheckBox_clicked() {
_ui.urlOnMobileLineEdit->setEnabled(!_ui.runLatestOnMobileCheckBox->isChecked());
}
void Nitpick::on_runFullSuiteOnMobileCheckBox_clicked() {
_ui.scriptURLOnMobileLineEdit->setEnabled(!_ui.runFullSuiteOnMobileCheckBox->isChecked());
}
void Nitpick::on_downloadAPKPushbutton_clicked() {
_testRunnerMobile->downloadAPK();
}

View file

@ -11,12 +11,10 @@
#define hifi_Nitpick_h
#include <QtWidgets/QMainWindow>
#include <QSignalMapper>
#include <QTextEdit>
#include "ui_Nitpick.h"
#include "Downloader.h"
#include "Test.h"
#include "TestCreator.h"
#include "TestRunnerDesktop.h"
#include "TestRunnerMobile.h"
@ -38,9 +36,6 @@ public:
void automaticTestRunEvaluationComplete(QString zippedFolderName, int numberOfFailures);
void downloadFile(const QUrl& url);
void downloadFiles(const QStringList& URLs, const QString& directoryName, const QStringList& filenames, void* caller);
void setUserText(const QString& user);
QString getSelectedUser();
@ -74,7 +69,9 @@ private slots:
void on_setWorkingFolderRunOnDesktopPushbutton_clicked();
void on_runNowPushbutton_clicked();
void on_usePreviousInstallationOnDesktopCheckBox_clicked();
void on_runLatestOnDesktopCheckBox_clicked();
void on_runFullSuiteOnDesktopCheckBox_clicked();
void on_updateTestRailRunResultsPushbutton_clicked();
@ -88,15 +85,16 @@ private slots:
void on_createWebPagePushbutton_clicked();
void saveFile(int index);
void about();
void content();
// Run on Mobile controls
void on_setWorkingFolderRunOnMobilePushbutton_clicked();
void on_connectDevicePushbutton_clicked();
void on_usePreviousInstallationOnMobileCheckBox_clicked();
void on_runLatestOnMobileCheckBox_clicked();
void on_runFullSuiteOnMobileCheckBox_clicked();
void on_downloadAPKPushbutton_clicked();
void on_installAPKPushbutton_clicked();
@ -106,28 +104,13 @@ private slots:
private:
Ui::NitpickClass _ui;
Test* _test{ nullptr };
TestCreator* _testCreator{ nullptr };
TestRunnerDesktop* _testRunnerDesktop{ nullptr };
TestRunnerMobile* _testRunnerMobile{ nullptr };
std::vector<Downloader*> _downloaders;
// local storage for parameters - folder to store downloaded files in, and a list of their names
QString _directoryName;
QStringList _filenames;
// Used to enable passing a parameter to slots
QSignalMapper* _signalMapper;
int _numberOfFilesToDownload{ 0 };
int _numberOfFilesDownloaded{ 0 };
int _index{ 0 };
bool _isRunningFromCommandline{ false };
void* _caller;
QStringList clientProfiles;
};

View file

@ -1,5 +1,5 @@
//
// Test.cpp
// TestCreator.cpp
//
// Created by Nissim Hadar on 2 Nov 2017.
// Copyright 2013 High Fidelity, Inc.
@ -7,7 +7,7 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Test.h"
#include "TestCreator.h"
#include <assert.h>
#include <QtCore/QTextStream>
@ -24,7 +24,9 @@ extern Nitpick* nitpick;
#include <math.h>
Test::Test(QProgressBar* progressBar, QCheckBox* checkBoxInteractiveMode) : _awsInterface(NULL) {
TestCreator::TestCreator(QProgressBar* progressBar, QCheckBox* checkBoxInteractiveMode) : _awsInterface(NULL) {
_downloader = new Downloader();
_progressBar = progressBar;
_checkBoxInteractiveMode = checkBoxInteractiveMode;
@ -36,7 +38,7 @@ Test::Test(QProgressBar* progressBar, QCheckBox* checkBoxInteractiveMode) : _aws
}
}
bool Test::createTestResultsFolderPath(const QString& directory) {
bool TestCreator::createTestResultsFolderPath(const QString& directory) {
QDateTime now = QDateTime::currentDateTime();
_testResultsFolderPath = directory + "/" + TEST_RESULTS_FOLDER + "--" + now.toString(DATETIME_FORMAT) + "(local)[" + QHostInfo::localHostName() + "]";
QDir testResultsFolder(_testResultsFolderPath);
@ -45,7 +47,7 @@ bool Test::createTestResultsFolderPath(const QString& directory) {
return QDir().mkdir(_testResultsFolderPath);
}
QString Test::zipAndDeleteTestResultsFolder() {
QString TestCreator::zipAndDeleteTestResultsFolder() {
QString zippedResultsFileName { _testResultsFolderPath + ".zip" };
QFileInfo fileInfo(zippedResultsFileName);
if (fileInfo.exists()) {
@ -65,7 +67,7 @@ QString Test::zipAndDeleteTestResultsFolder() {
return zippedResultsFileName;
}
int Test::compareImageLists() {
int TestCreator::compareImageLists() {
_progressBar->setMinimum(0);
_progressBar->setMaximum(_expectedImagesFullFilenames.length() - 1);
_progressBar->setValue(0);
@ -136,7 +138,7 @@ int Test::compareImageLists() {
return numberOfFailures;
}
int Test::checkTextResults() {
int TestCreator::checkTextResults() {
// Create lists of failed and passed tests
QStringList nameFilterFailed;
nameFilterFailed << "*.failed.txt";
@ -146,7 +148,7 @@ int Test::checkTextResults() {
nameFilterPassed << "*.passed.txt";
QStringList testsPassed = QDir(_snapshotDirectory).entryList(nameFilterPassed, QDir::Files, QDir::Name);
// Add results to Test Results folder
// Add results to TestCreator Results folder
foreach(QString currentFilename, testsFailed) {
appendTestResultsToFile(currentFilename, true);
}
@ -158,7 +160,7 @@ int Test::checkTextResults() {
return testsFailed.length();
}
void Test::appendTestResultsToFile(const TestResult& testResult, const QPixmap& comparisonImage, const QPixmap& ssimResultsImage, bool hasFailed) {
void TestCreator::appendTestResultsToFile(const TestResult& testResult, const QPixmap& comparisonImage, const QPixmap& ssimResultsImage, bool hasFailed) {
// Critical error if Test Results folder does not exist
if (!QDir().exists(_testResultsFolderPath)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Folder " + _testResultsFolderPath + " not found");
@ -193,7 +195,7 @@ void Test::appendTestResultsToFile(const TestResult& testResult, const QPixmap&
// Create text file describing the failure
QTextStream stream(&descriptionFile);
stream << "Test in folder " << testResult._pathname.left(testResult._pathname.length() - 1) << endl; // remove trailing '/'
stream << "TestCreator in folder " << testResult._pathname.left(testResult._pathname.length() - 1) << endl; // remove trailing '/'
stream << "Expected image was " << testResult._expectedImageFilename << endl;
stream << "Actual image was " << testResult._actualImageFilename << endl;
stream << "Similarity index was " << testResult._error << endl;
@ -224,7 +226,7 @@ void Test::appendTestResultsToFile(const TestResult& testResult, const QPixmap&
ssimResultsImage.save(resultFolderPath + "/" + "SSIM Image.png");
}
void::Test::appendTestResultsToFile(QString testResultFilename, bool hasFailed) {
void::TestCreator::appendTestResultsToFile(QString testResultFilename, bool hasFailed) {
// The test name includes everything until the penultimate period
QString testNameTemp = testResultFilename.left(testResultFilename.lastIndexOf('.'));
QString testName = testResultFilename.left(testNameTemp.lastIndexOf('.'));
@ -251,7 +253,7 @@ void::Test::appendTestResultsToFile(QString testResultFilename, bool hasFailed)
}
}
void Test::startTestsEvaluation(const bool isRunningFromCommandLine,
void TestCreator::startTestsEvaluation(const bool isRunningFromCommandLine,
const bool isRunningInAutomaticTestRun,
const QString& snapshotDirectory,
const QString& branchFromCommandLine,
@ -324,10 +326,11 @@ void Test::startTestsEvaluation(const bool isRunningFromCommandLine,
}
}
nitpick->downloadFiles(expectedImagesURLs, _snapshotDirectory, _expectedImagesFilenames, (void *)this);
_downloader->downloadFiles(expectedImagesURLs, _snapshotDirectory, _expectedImagesFilenames, (void *)this);
finishTestsEvaluation();
}
void Test::finishTestsEvaluation() {
void TestCreator::finishTestsEvaluation() {
// First - compare the pairs of images
int numberOfFailures = compareImageLists();
@ -353,7 +356,7 @@ void Test::finishTestsEvaluation() {
}
}
bool Test::isAValidDirectory(const QString& pathname) {
bool TestCreator::isAValidDirectory(const QString& pathname) {
// Only process directories
QDir dir(pathname);
if (!dir.exists()) {
@ -368,7 +371,7 @@ bool Test::isAValidDirectory(const QString& pathname) {
return true;
}
QString Test::extractPathFromTestsDown(const QString& fullPath) {
QString TestCreator::extractPathFromTestsDown(const QString& fullPath) {
// `fullPath` includes the full path to the test. We need the portion below (and including) `tests`
QStringList pathParts = fullPath.split('/');
int i{ 0 };
@ -389,14 +392,14 @@ QString Test::extractPathFromTestsDown(const QString& fullPath) {
return partialPath;
}
void Test::includeTest(QTextStream& textStream, const QString& testPathname) {
void TestCreator::includeTest(QTextStream& textStream, const QString& testPathname) {
QString partialPath = extractPathFromTestsDown(testPathname);
QString partialPathWithoutTests = partialPath.right(partialPath.length() - 7);
textStream << "Script.include(testsRootPath + \"" << partialPathWithoutTests + "\");" << endl;
}
void Test::createTests(const QString& clientProfile) {
void TestCreator::createTests(const QString& clientProfile) {
// Rename files sequentially, as ExpectedResult_00000.png, ExpectedResult_00001.png and so on
// Any existing expected result images will be deleted
QString previousSelection = _snapshotDirectory;
@ -474,7 +477,7 @@ void Test::createTests(const QString& clientProfile) {
QMessageBox::information(0, "Success", "Test images have been created");
}
ExtractedText Test::getTestScriptLines(QString testFileName) {
ExtractedText TestCreator::getTestScriptLines(QString testFileName) {
ExtractedText relevantTextFromTest;
QFile inputFile(testFileName);
@ -539,7 +542,7 @@ ExtractedText Test::getTestScriptLines(QString testFileName) {
return relevantTextFromTest;
}
bool Test::createFileSetup() {
bool TestCreator::createFileSetup() {
// Folder selection
QString previousSelection = _testDirectory;
QString parent = previousSelection.left(previousSelection.lastIndexOf('/'));
@ -559,7 +562,7 @@ bool Test::createFileSetup() {
return true;
}
bool Test::createAllFilesSetup() {
bool TestCreator::createAllFilesSetup() {
// Select folder to start recursing from
QString previousSelection = _testsRootDirectory;
QString parent = previousSelection.left(previousSelection.lastIndexOf('/'));
@ -581,7 +584,7 @@ bool Test::createAllFilesSetup() {
// Create an MD file for a user-selected test.
// The folder selected must contain a script named "test.js", the file produced is named "test.md"
void Test::createMDFile() {
void TestCreator::createMDFile() {
if (!createFileSetup()) {
return;
}
@ -591,7 +594,7 @@ void Test::createMDFile() {
}
}
void Test::createAllMDFiles() {
void TestCreator::createAllMDFiles() {
if (!createAllFilesSetup()) {
return;
}
@ -623,7 +626,7 @@ void Test::createAllMDFiles() {
QMessageBox::information(0, "Success", "MD files have been created");
}
bool Test::createMDFile(const QString& directory) {
bool TestCreator::createMDFile(const QString& directory) {
// Verify folder contains test.js file
QString testFileName(directory + "/" + TEST_FILENAME);
QFileInfo testFileInfo(testFileName);
@ -643,7 +646,7 @@ bool Test::createMDFile(const QString& directory) {
QTextStream stream(&mdFile);
//Test title
//TestCreator title
QString testName = testScriptLines.title;
stream << "# " << testName << "\n";
@ -675,7 +678,7 @@ bool Test::createMDFile(const QString& directory) {
return true;
}
void Test::createTestAutoScript() {
void TestCreator::createTestAutoScript() {
if (!createFileSetup()) {
return;
}
@ -685,7 +688,7 @@ void Test::createTestAutoScript() {
}
}
void Test::createAllTestAutoScripts() {
void TestCreator::createAllTestAutoScripts() {
if (!createAllFilesSetup()) {
return;
}
@ -717,7 +720,7 @@ void Test::createAllTestAutoScripts() {
QMessageBox::information(0, "Success", "All 'testAuto.js' scripts have been created");
}
bool Test::createTestAutoScript(const QString& directory) {
bool TestCreator::createTestAutoScript(const QString& directory) {
// Verify folder contains test.js file
QString testFileName(directory + "/" + TEST_FILENAME);
QFileInfo testFileInfo(testFileName);
@ -748,7 +751,7 @@ bool Test::createTestAutoScript(const QString& directory) {
// Creates a single script in a user-selected folder.
// This script will run all text.js scripts in every applicable sub-folder
void Test::createRecursiveScript() {
void TestCreator::createRecursiveScript() {
if (!createFileSetup()) {
return;
}
@ -758,7 +761,7 @@ void Test::createRecursiveScript() {
}
// This method creates a `testRecursive.js` script in every sub-folder.
void Test::createAllRecursiveScripts() {
void TestCreator::createAllRecursiveScripts() {
if (!createAllFilesSetup()) {
return;
}
@ -768,7 +771,7 @@ void Test::createAllRecursiveScripts() {
QMessageBox::information(0, "Success", "Scripts have been created");
}
void Test::createAllRecursiveScripts(const QString& directory) {
void TestCreator::createAllRecursiveScripts(const QString& directory) {
QDirIterator it(directory, QDirIterator::Subdirectories);
while (it.hasNext()) {
@ -780,7 +783,7 @@ void Test::createAllRecursiveScripts(const QString& directory) {
}
}
void Test::createRecursiveScript(const QString& directory, bool interactiveMode) {
void TestCreator::createRecursiveScript(const QString& directory, bool interactiveMode) {
// If folder contains a test, then we are at a leaf
const QString testPathname{ directory + "/" + TEST_FILENAME };
if (QFileInfo(testPathname).exists()) {
@ -846,7 +849,10 @@ void Test::createRecursiveScript(const QString& directory, bool interactiveMode)
textStream << " nitpick = createNitpick(Script.resolvePath(\".\"));" << endl;
textStream << " testsRootPath = nitpick.getTestsRootPath();" << endl << endl;
textStream << " nitpick.enableRecursive();" << endl;
textStream << " nitpick.enableAuto();" << endl;
textStream << " nitpick.enableAuto();" << endl << endl;
textStream << " if (typeof Test !== 'undefined') {" << endl;
textStream << " Test.wait(10000);" << endl;
textStream << " }" << endl;
textStream << "} else {" << endl;
textStream << " depth++" << endl;
textStream << "}" << endl << endl;
@ -866,7 +872,7 @@ void Test::createRecursiveScript(const QString& directory, bool interactiveMode)
recursiveTestsFile.close();
}
void Test::createTestsOutline() {
void TestCreator::createTestsOutline() {
QString previousSelection = _testDirectory;
QString parent = previousSelection.left(previousSelection.lastIndexOf('/'));
if (!parent.isNull() && parent.right(1) != "/") {
@ -892,7 +898,7 @@ void Test::createTestsOutline() {
QTextStream stream(&mdFile);
//Test title
//TestCreator title
stream << "# Outline of all tests\n";
stream << "Directories with an appended (*) have an automatic test\n\n";
@ -950,10 +956,10 @@ void Test::createTestsOutline() {
mdFile.close();
QMessageBox::information(0, "Success", "Test outline file " + testsOutlineFilename + " has been created");
QMessageBox::information(0, "Success", "TestCreator outline file " + testsOutlineFilename + " has been created");
}
void Test::createTestRailTestCases() {
void TestCreator::createTestRailTestCases() {
QString previousSelection = _testDirectory;
QString parent = previousSelection.left(previousSelection.lastIndexOf('/'));
if (!parent.isNull() && parent.right(1) != "/") {
@ -990,7 +996,7 @@ void Test::createTestRailTestCases() {
}
}
void Test::createTestRailRun() {
void TestCreator::createTestRailRun() {
QString outputDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select a folder to store generated files in",
nullptr, QFileDialog::ShowDirsOnly);
@ -1006,9 +1012,9 @@ void Test::createTestRailRun() {
_testRailInterface->createTestRailRun(outputDirectory);
}
void Test::updateTestRailRunResult() {
void TestCreator::updateTestRailRunResult() {
QString testResults = QFileDialog::getOpenFileName(nullptr, "Please select the zipped test results to update from", nullptr,
"Zipped Test Results (*.zip)");
"Zipped TestCreator Results (*.zip)");
if (testResults.isNull()) {
return;
}
@ -1027,7 +1033,7 @@ void Test::updateTestRailRunResult() {
_testRailInterface->updateTestRailRunResults(testResults, tempDirectory);
}
QStringList Test::createListOfAll_imagesInDirectory(const QString& imageFormat, const QString& pathToImageDirectory) {
QStringList TestCreator::createListOfAll_imagesInDirectory(const QString& imageFormat, const QString& pathToImageDirectory) {
_imageDirectory = QDir(pathToImageDirectory);
QStringList nameFilters;
nameFilters << "*." + imageFormat;
@ -1039,7 +1045,7 @@ QStringList Test::createListOfAll_imagesInDirectory(const QString& imageFormat,
// Filename (i.e. without extension) contains tests (this is based on all test scripts being within the tests folder)
// Last 5 characters in filename are digits (after removing the extension)
// Extension is 'imageFormat'
bool Test::isInSnapshotFilenameFormat(const QString& imageFormat, const QString& filename) {
bool TestCreator::isInSnapshotFilenameFormat(const QString& imageFormat, const QString& filename) {
bool contains_tests = filename.contains("tests" + PATH_SEPARATOR);
QString filenameWithoutExtension = filename.left(filename.lastIndexOf('.'));
@ -1054,7 +1060,7 @@ bool Test::isInSnapshotFilenameFormat(const QString& imageFormat, const QString&
// For a file named "D_GitHub_hifi-tests_tests_content_entity_zone_create_0.jpg", the test directory is
// D:/GitHub/hifi-tests/tests/content/entity/zone/create
// This method assumes the filename is in the correct format
QString Test::getExpectedImageDestinationDirectory(const QString& filename) {
QString TestCreator::getExpectedImageDestinationDirectory(const QString& filename) {
QString filenameWithoutExtension = filename.left(filename.length() - 4);
QStringList filenameParts = filenameWithoutExtension.split(PATH_SEPARATOR);
@ -1071,7 +1077,7 @@ QString Test::getExpectedImageDestinationDirectory(const QString& filename) {
// is ...tests/content/entity/zone/create
// This is used to create the full URL
// This method assumes the filename is in the correct format
QString Test::getExpectedImagePartialSourceDirectory(const QString& filename) {
QString TestCreator::getExpectedImagePartialSourceDirectory(const QString& filename) {
QString filenameWithoutExtension = filename.left(filename.length() - 4);
QStringList filenameParts = filenameWithoutExtension.split(PATH_SEPARATOR);
@ -1096,18 +1102,18 @@ QString Test::getExpectedImagePartialSourceDirectory(const QString& filename) {
return result;
}
void Test::setTestRailCreateMode(TestRailCreateMode testRailCreateMode) {
void TestCreator::setTestRailCreateMode(TestRailCreateMode testRailCreateMode) {
_testRailCreateMode = testRailCreateMode;
}
void Test::createWebPage(
void TestCreator::createWebPage(
QCheckBox* updateAWSCheckBox,
QRadioButton* diffImageRadioButton,
QRadioButton* ssimImageRadionButton,
QLineEdit* urlLineEdit
) {
QString testResults = QFileDialog::getOpenFileName(nullptr, "Please select the zipped test results to update from", nullptr,
"Zipped Test Results (TestResults--*.zip)");
"Zipped TestCreator Results (TestResults--*.zip)");
if (testResults.isNull()) {
return;
}

View file

@ -1,5 +1,5 @@
//
// Test.h
// TestCreator.h
//
// Created by Nissim Hadar on 2 Nov 2017.
// Copyright 2013 High Fidelity, Inc.
@ -8,8 +8,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_test_h
#define hifi_test_h
#ifndef hifi_testCreator_h
#define hifi_testCreator_h
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QMessageBox>
@ -18,6 +18,7 @@
#include "AWSInterface.h"
#include "ImageComparer.h"
#include "Downloader.h"
#include "MismatchWindow.h"
#include "TestRailInterface.h"
@ -40,9 +41,9 @@ enum TestRailCreateMode {
XML
};
class Test {
class TestCreator {
public:
Test(QProgressBar* progressBar, QCheckBox* checkBoxInteractiveMode);
TestCreator(QProgressBar* progressBar, QCheckBox* checkBoxInteractiveMode);
void startTestsEvaluation(const bool isRunningFromCommandLine,
const bool isRunningInAutomaticTestRun,
@ -167,6 +168,7 @@ private:
TestRailCreateMode _testRailCreateMode { PYTHON };
AWSInterface* _awsInterface;
Downloader* _downloader;
};
#endif // hifi_test_h
#endif

View file

@ -9,7 +9,7 @@
//
#include "TestRailInterface.h"
#include "Test.h"
#include "TestCreator.h"
#include <quazip5/quazip.h>
#include <quazip5/JlCompress.h>
@ -258,7 +258,7 @@ bool TestRailInterface::requestTestRailResultsDataFromUser() {
}
bool TestRailInterface::isAValidTestDirectory(const QString& directory) {
if (Test::isAValidDirectory(directory)) {
if (TestCreator::isAValidDirectory(directory)) {
// Ignore the utils and preformance directories
if (directory.right(QString("utils").length()) == "utils" ||
directory.right(QString("performance").length()) == "performance") {

Some files were not shown because too many files have changed in this diff Show more