Skip to content

Commit

Permalink
README追加
Browse files Browse the repository at this point in the history
  • Loading branch information
mino0123 committed Feb 5, 2013
1 parent 97837a6 commit 2c2a703
Show file tree
Hide file tree
Showing 16 changed files with 417 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.*
!.git*
/node_modules
8 changes: 8 additions & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,17 @@ module.exports = function (grunt) {
run: true
}
}
},
screenshot: {
options: grunt.file.readJSON('.screenshot'),
//{loginUrl, username, password, targetUrl}
dist: {
dest: 'README.md'
}
}
});

grunt.loadTasks('tasks');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
Expand Down
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@

### これなに
Salesforceのオブジェクト定義やメタデータを参照したり、retrieve/deployができる
Scriptish スクリプトです。

### インストール
0. [Scriptish](https://addons.mozilla.org/ja/firefox/addon/scriptish/)をインストール
0. [forcedotcommetadatatool.user.js](https://raw.github.com/mino0123/Force.com-Metadata-Tool/master/forcedotcommetadatatool.user.js)をインストール

### 使い方
インストール後、SalesforceにログインしてからVisualforce以外の画面で左上のロゴをクリックすることで使用できます。

![click target](img/click_target.png)

オブジェクトの一覧が画面上に表示されます。
![global describe](img/global_describe.png)

### オブジェクト一覧
オブジェクト一覧画面には、オブジェクト名、設定へのリンク、ビューへのリンクが表示されます。
![global describe detail](img/global_describe_detail.png)
* オブジェクトの詳細を表示します
* setup カスタムオブジェクトのみ表示されます。設定画面へのリンクです。
* view /{keyprefix} へのリンクです。対応しているオブジェクトならビューが表示されますが、サポートされてないオブジェクトもあります

### オブジェクト詳細

* 項目一覧

![sobject fields](img/sobject_fields.png)

* 子リレーション

![sobject childrelationships](img/sobject_childrelationships.png)

* レコードタイプ

![sobject recordtypes](img/sobject_recordtypes.png)

* 詳細

![sobject detail](img/sobject_detail.png)

* 表示項目 (「項目一覧」で表示される項目のプロパティを設定できます)

![sobject config](img/sobject_config.png)

<!--
### メタデータ
![sobject detail](img/metadata_describe.png)
### メタデータ詳細
### Retrieve/Deploy
単一ファイルの retrieve/deploy ができます。
* name
* member
* file
* directory
* basename
* extension
* meta file
-->
Binary file added img/click_target.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/global_describe.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/global_describe_detail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/metadata_describe.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/sobject_childrelationships.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/sobject_config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/sobject_detail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/sobject_fields.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/sobject_recordtypes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"grunt-contrib-jshint": "~0.1.1rc6",
"grunt-contrib-concat": "~0.1.2rc6",
"grunt-contrib-watch": "~0.2.0rc5",
"grunt-mocha": "git://github.com/kmiyashiro/grunt-mocha.git"
"grunt-mocha": "git://github.com/kmiyashiro/grunt-mocha.git",
"grunt-lib-phantomjs": "~0.1.0"
}
}
11 changes: 11 additions & 0 deletions tasks/phantomjs/inject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function GM_addStyle(css) {
jQuery(function () {
var el = document.createElement('style');
el.type = 'text/css';
el.innerHTML = css;
document.head.appendChild(el);
});
}
function GM_getValue(name) {
return undefined;
}
273 changes: 273 additions & 0 deletions tasks/phantomjs/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
/*
* grunt-lib-phantomjs
* http://gruntjs.com/
*
* Modified by Yuta Minowa
*
* Copyright (c) 2012 "Cowboy" Ben Alman, contributors
* Licensed under the MIT license.
*/

/*global phantom:true*/

'use strict';


var fs = require('fs');

// The temporary file used for communications.
var tmpfile = phantom.args[0];
// The page .html file to load.
var url = phantom.args[1];
// Extra, optionally overridable stuff.
var options = JSON.parse(phantom.args[2] || {});

// Default options.
if (!options.timeout) { options.timeout = 5000; }

// Keep track of the last time a client message was sent.
var last = new Date();

// Messages are sent to the parent by appending them to the tempfile.
var sendMessage = function(arg) {
var args = Array.isArray(arg) ? arg : [].slice.call(arguments);
last = new Date();
fs.write(tmpfile, JSON.stringify(args) + '\n', 'a');
};

// This allows grunt to abort if the PhantomJS version isn't adequate.
sendMessage('private', 'version', phantom.version);

// Abort if the page doesn't send any messages for a while.
setInterval(function() {
if (new Date() - last > options.timeout) {
sendMessage('fail.timeout');
phantom.exit();
}
}, 100);

// Create a new page.
var page = require('webpage').create();

// Inject bridge script into client page.
var injected;
var inject = function() {
if (injected) { return; }
// Inject client-side helper script.
sendMessage('inject', options.inject);
page.injectJs(options.inject);
injected = true;
};

// Keep track if the client-side helper script already has been injected.
page.onUrlChanged = function(newUrl) {
injected = false;
sendMessage('onUrlChanged', newUrl);
};

// The client page must send its messages via alert(jsonstring).
page.onAlert = function(str) {
// The only thing that should ever alert "inject" is the custom event
// handler this script adds to be executed on DOMContentLoaded.
if (str === 'inject') {
inject();
return;
}
// Otherwise, parse the specified message string and send it back to grunt.
// Unless there's a parse error. Then, complain.
try {
sendMessage(JSON.parse(str));
} catch(err) {
sendMessage('error.invalidJSON', str);
}
};

// Relay console logging messages.
page.onConsoleMessage = function(message) {
sendMessage('console', message);
};

// For debugging.
page.onResourceRequested = function(request) {
sendMessage('onResourceRequested', request.url);
};

page.onResourceReceived = function(request) {
if (request.stage === 'end') {
sendMessage('onResourceReceived', request.url);
}
};

page.onError = function(msg, trace) {
sendMessage('error.onError', msg, trace);
phantom.exit();
};

// Run before the page is loaded.
page.onInitialized = function() {
sendMessage('onInitialized');

// Customization for mocha, passing mocha options from task config
page.evaluate(function(options) {
window.PHANTOMJS = options;
}, options);

// Abort if there is no bridge to inject.
if (!options.inject) { return; }
// Tell the client that when DOMContentLoaded fires, it needs to tell this
// script to inject the bridge. This should ensure that the bridge gets
// injected before any other DOMContentLoaded or window.load event handler.
page.evaluate(function() {
/*jshint browser:true, devel:true */
document.addEventListener('DOMContentLoaded', function() {
alert('inject');
}, false);
});
};

function setOnLoadFinished(callback, filter) {
page.onLoadFinished = function (status) {
var currentUrl = page.url;
sendMessage('onLoadFinished', currentUrl);
if (status !== 'success') {
sendMessage('log', status);
sendMessage('fail.load', currentUrl);
phantom.exit();
} else {
if (filter && !(page.evaluate(filter))) {
return;
}
try {
callback();
} catch(e) {
sendMessage('error', e);
}
}
};
}

// ログイン画面ではエラーを無視する
// "ReferenceError: Can't find variable: loader Use --force to continue."
var _onError = page.onError;
page.onError = function () {};
setOnLoadFinished(onLoginOpen);
function onLoginOpen() {
setOnLoadFinished(function () {
sendMessage('log', 'login end');
sendMessage('log', options.targetUrl);
onLoginEnd();
}, function () {
return !!ApiUtils && !!ApiUtils.getSessionId();// has session id
});
page.evaluate(function (un, pw) {
document.getElementById('username').value = un;
document.getElementById('password').value = pw;
document.getElementById('Login').click();
}, options.username, options.password);
page.onError = _onError;
}
function onLoginEnd() {
setOnLoadFinished(onTargetPageOpen);
page.open(options.targetUrl);
}
function onTargetPageOpen() {
try {
injectJsFiles();
captureLogo();
captureGlobalDescribe();
} catch (e) {
sendMessage('error', e);
}
}
function injectJsFiles() {
page.injectJs('tasks/phantomjs/inject.js');
page.injectJs('lib/jquery-1.8.3.min.js');
page.injectJs('lib/Hogan.js/hogan-2.0.0.min.js');
page.injectJs('lib/JSZip/jszip.js');
page.injectJs('lib/JSZip/jszip-load.js');
page.injectJs('lib/JSZip/jszip-inflate.js');
page.injectJs('lib/JSZip/jszip-deflate.js');
page.injectJs('forcedotcommetadatatool.user.js');
}
function wait(callback, filter) {
function loop() {
if (page.evaluate(filter)) {
callback();
} else {
setTimeout(loop, 300);
}
}
loop();
}
function captureLogo() {
page.evaluate(function () {
document.getElementById('phHeaderLogoImage').style.border = '2px solid red';
});
page.clipRect = { top: 0, left: 0, width: 300, height: 100 };
page.render('img/click_target.png');
page.clipRect = {};
page.evaluate(function () {
document.getElementById('phHeaderLogoImage').style.border = null;
});
}
function captureGlobalDescribe() {
wait(function () {
wait(function () {
page.clipRect = { top: 0, left: 0, width: 1200, height: 800 };
page.render('img/global_describe.png');
page.clipRect = { top: 40, left: 80, width: 340, height: 50 };
page.render('img/global_describe_detail.png');
page.clipRect = {};
captureSObject();
}, function() {
return MetadataTool.Panel.css('display') === 'block';
});
page.evaluate(function() {
MetadataTool.$.trigger('run');
})
}, function () {
return typeof sforce === 'object' && !!sforce.metadata;
});
}
function captureSObject() {
wait(function () {
function clickListItem(title) {
page.evaluate(function (title) {
jQuery('li[data-title="' + title + '"]').trigger('click');
}, title);
}
page.clipRect = { top: 0, left: 0, width: 500, height: 250 };
page.render('img/sobject_fields.png');
clickListItem('子リレーション');
page.render('img/sobject_childrelationships.png');
clickListItem('レコードタイプ');
page.render('img/sobject_recordtypes.png');
clickListItem('詳細');
page.render('img/sobject_detail.png');
clickListItem('表示項目');
page.render('img/sobject_config.png');
page.clipRect = {};
captureMetadata();
}, function () {
return document.getElementsByClassName('mt-sod-table').length > 0;
});
page.evaluate(function () {
MetadataTool.DescribeSObject.$.trigger('run', 'Account');
});
}
function captureMetadata() {
wait(function () {
page.render('img/metadata_describe.png');
phantom.exit();
}, function () {
return !!MetadataTool.DescribeMetadata.el;
});
page.evaluate(function() {
// MetadataTool.DescribeMetadata.$.trigger('run');
jQuery('#md').trigger('click');
});
}

page.viewportSize = { width: 1200, height: 800 };

page.open(options.loginUrl);
Loading

0 comments on commit 2c2a703

Please sign in to comment.