2011-11-23 05:28:39 +00:00
angular . module ( 'ngdocs.directives' , [ ] , function ( $compileProvider ) {
2011-01-19 23:42:11 +00:00
2010-11-10 23:31:15 +00:00
var angularJsUrl ;
var scripts = document . getElementsByTagName ( "script" ) ;
2011-02-22 22:48:53 +00:00
var angularJsRegex = /^(|.*\/)angular(-.*?)?(\.min)?.js(\?[^#]*)?(#(.*))?$/ ;
2010-11-10 23:31:15 +00:00
for ( var j = 0 ; j < scripts . length ; j ++ ) {
var src = scripts [ j ] . src ;
2011-02-04 22:09:17 +00:00
if ( src && src . match ( angularJsRegex ) ) {
2011-01-18 22:15:53 +00:00
angularJsUrl = src . replace ( 'docs.angularjs.org' , 'code.angularjs.org' ) ;
2011-02-04 22:09:17 +00:00
continue ;
2010-11-10 23:31:15 +00:00
}
}
2011-01-19 23:42:11 +00:00
2010-11-06 04:12:37 +00:00
var HTML _TEMPLATE =
2012-01-07 02:10:47 +00:00
'<!doctype html>\n' +
'<html xmlns:ng="http://angularjs.org" ng:app_MODULE_>\n' +
' <script src="' + angularJsUrl + '"></script>\n' +
'_SCRIPT_SOURCE_' +
' <body>\n' +
'_HTML_SOURCE_\n' +
' </body>\n' +
'</html>' ;
2010-11-06 04:12:37 +00:00
2011-11-23 05:28:39 +00:00
$compileProvider . directive ( 'docExample' , [ '$injector' , '$log' , '$browser' , '$location' ,
function ( $injector , $log , $browser , $location ) {
return {
terminal : true ,
compile : function ( element , attrs ) {
2011-12-14 01:55:31 +00:00
var module = attrs . module ;
2011-11-23 05:28:39 +00:00
//jQuery find() methods in this widget contain primitive selectors on purpose so that we can use
//jqlite instead. jqlite's find() method currently supports onlt getElementsByTagName!
var example = element . find ( 'pre' ) . eq ( 0 ) , //doc-source
scriptSrc = '' ,
htmlSrc = example . text ( ) . replace ( /<script[^\>]*>([\s\S]+)<\/script>/im , function ( _ , script ) {
scriptSrc = script ;
return '' ;
} ) ,
showSource = example . attr ( 'source' ) !== 'false' ,
jsfiddle = example . attr ( 'jsfiddle' ) || true ,
scenario = element . find ( 'pre' ) . eq ( 1 ) ; //doc-scenario
var tabs = angular . element ( '<ul class="doc-example">' ) ;
// show source tab, if not disabled
if ( showSource ) {
tabs . append (
'<li class="doc-example-heading"><h3>Source</h3></li>' +
'<li class="doc-example-source" ng:non-bindable>' +
jsFiddleButton ( jsfiddle ) + // may or may not have value
'<pre class="brush: js; html-script: true; toolbar: false;"></pre></li>' ) ;
}
// show live preview tab
var livePreviewTab ;
tabs . append ( '<li class="doc-example-heading"><h3>Live Preview</h3></li>' ) ;
tabs . append ( livePreviewTab = angular . element ( '<li class="doc-example-live">' + htmlSrc + '</li>' ) ) ;
// show scenario tab, if present
if ( scenario . text ( ) ) {
tabs . append (
'<li class="doc-example-heading"><h3>Scenario Test</h3></li>' +
'<li class="doc-example-scenario"><pre class="brush: js">' + scenario . text ( ) + '</pre></li>' ) ;
}
2010-11-06 04:12:37 +00:00
2011-11-23 05:28:39 +00:00
tabs . find ( 'li' ) . eq ( 1 ) . find ( 'pre' ) . text (
HTML _TEMPLATE .
replace ( '_SCRIPT_SOURCE_' , scriptSrc ? ' <script>\n' + indent ( scriptSrc , ' ' ) + '\n </script>\n' : '' ) .
replace ( '_HTML_SOURCE_' , indent ( htmlSrc , ' ' ) ) .
replace ( '_MODULE_' , module ? '="' + module + '"' : '' ) ) ;
2010-11-06 04:12:37 +00:00
2011-11-23 05:28:39 +00:00
element . html ( '' ) ;
element . append ( tabs ) ;
2011-08-11 03:53:56 +00:00
2011-11-23 05:28:39 +00:00
try {
if ( window . execScript ) { // IE
window . execScript ( scriptSrc || '"stupid IE!"' ) ; // IE complains when evaling empty string
} else {
window . eval ( scriptSrc ) ;
}
} catch ( e ) {
alert ( e ) ;
2012-01-12 19:06:10 +00:00
}
2011-11-14 23:58:40 +00:00
2011-11-23 05:28:39 +00:00
return function ( docsAppScope ) {
var modules = [
function ( $provide ) {
$provide . value ( '$browser' , $browser ) ;
$provide . value ( '$location' , $location ) ;
2011-12-14 01:55:31 +00:00
$provide . decorator ( '$defer' , function ( $rootScope , $delegate ) {
return angular . extend ( function ( fn , delay ) {
if ( delay && delay > 500 ) {
return setTimeout ( function ( ) {
$rootScope . $apply ( fn ) ;
} , delay ) ;
} else {
return $delegate . apply ( this , arguments ) ;
}
} , $delegate ) ;
} ) ;
2011-11-23 05:28:39 +00:00
}
] ;
module && modules . push ( module ) ;
angular . bootstrap ( livePreviewTab , modules ) .
invoke ( [ '$rootScope' , function ( example$rootScope ) {
element . bind ( '$destroy' , docsAppScope . $root . $watch ( function ( ) {
// this propagates the $watch from the docs app to the example app
example$rootScope . $digest ( ) ;
} ) ) ;
} ] ) ;
} ;
function jsFiddleButton ( jsfiddle ) {
var fixJsFiddleIssue132 = true ;
if ( jsfiddle !== 'false' ) {
if ( jsfiddle === true ) {
//dynamically generate a fiddle
var fiddleUrl = 'http://jsfiddle.net/api/post/library/pure/' ;
function jsFiddleEscape ( text , prefix ) {
return indent ( text . replace ( /<\/textarea>/gi , '</textarea>' ) , prefix ) ;
}
return '<form class="jsfiddle" method="post" action="' + fiddleUrl + '" target="_blank">' +
( fixJsFiddleIssue132 ? '' : '<textarea name="resources">' + angularJsUrl + '</textarea>' ) +
'<textarea name="css">\n' +
( fixJsFiddleIssue132 ? '</style>\n<script src="' + angularJsUrl + '"></script>\n<style>\n' : '' ) +
'.ng-invalid { border: 1px solid red; } \n' +
'body { font-family: Arial,Helvetica,sans-serif; }\n' +
'body, td, th { font-size: 14px; margin: 0; }\n' +
'table { border-collapse: separate; border-spacing: 2px; display: table; margin-bottom: 0; margin-top: 0; -moz-box-sizing: border-box; text-indent: 0; }\n' +
'a:link, a:visited, a:hover { color: #5D6DB6; text-decoration: none; }\n' +
'.error { color: red; }\n' +
'</textarea>' +
'<input type="text" name="title" value="AngularJS Live Example">' +
'<textarea name="html">' +
'<div ng:app' + ( module ? '="' + module + '"' : '' ) + '>\n' + jsFiddleEscape ( htmlSrc , ' ' ) + '\n</div>' +
'</textarea>' +
'<textarea name="js">' + jsFiddleEscape ( scriptSrc ) + '</textarea>' +
'<button>edit at jsFiddle</button>' +
'</form>' ;
} else {
//use existing fiddle
fiddleUrl = "http://jsfiddle.net" + jsfiddle ;
return '<form class="jsfiddle" method="get" action="' + fiddleUrl + '" target="_blank">' +
'<button>edit at jsFiddle</button>' +
'</form>' ;
}
2012-01-07 02:10:47 +00:00
}
2011-11-23 05:28:39 +00:00
} ;
2011-08-11 03:53:56 +00:00
}
}
2011-11-14 23:58:40 +00:00
} ] ) ;
2011-01-19 23:42:11 +00:00
2012-01-07 02:10:47 +00:00
function indent ( text , prefix ) {
prefix = prefix || '' ;
2011-01-31 19:55:44 +00:00
if ( ! text ) return text ;
2011-04-07 19:34:34 +00:00
var lines = text . split ( /\r?\n/ ) ;
2011-11-12 01:15:22 +00:00
var i ;
2011-01-26 05:55:11 +00:00
// remove any leading blank lines
2010-11-10 23:31:15 +00:00
while ( lines [ 0 ] . match ( /^\s*$/ ) ) lines . shift ( ) ;
2011-01-26 05:55:11 +00:00
// remove any trailing blank lines
2010-11-10 23:31:15 +00:00
while ( lines [ lines . length - 1 ] . match ( /^\s*$/ ) ) lines . pop ( ) ;
2011-01-26 05:55:11 +00:00
var minIndent = 999 ;
2011-11-12 01:15:22 +00:00
for ( i = 0 ; i < lines . length ; i ++ ) {
2011-01-26 05:55:11 +00:00
var line = lines [ 0 ] ;
var indent = line . match ( /^\s*/ ) [ 0 ] ;
if ( indent !== line && indent . length < minIndent ) {
minIndent = indent . length ;
}
}
2011-11-12 01:15:22 +00:00
for ( i = 0 ; i < lines . length ; i ++ ) {
2012-01-07 02:10:47 +00:00
lines [ i ] = prefix + lines [ i ] . substring ( minIndent ) ;
2010-11-10 23:31:15 +00:00
}
2012-01-07 02:10:47 +00:00
return lines . join ( '\n' ) ;
2011-11-12 01:15:22 +00:00
}
2011-01-19 23:42:11 +00:00
2011-11-23 05:28:39 +00:00
$compileProvider . directive ( 'docTutorialInstructions' , function ( ) {
var HTML _NAV = '<li ng:class="currentCls(\'{id}\')"><a ng:click="select(\'{id}\')" href>{title}</a></li>' ;
var HTML _CONTENT = '<div ng:show="selected==\'{id}\'">{content}</div>' ;
var HTML _TPL =
'<p><a ng:init="showInstructions = {show}" ng:show="!showInstructions" ng:click="showInstructions = true" href>Workspace Reset Instructions ➤</a></p>' +
'<div ng:controller="TutorialInstructionsCtrl" ng:show="showInstructions">' +
'<div class="tabs-nav">' +
'<ul>' +
'</ul>' +
'</div>' +
'<div class="tabs-content"><div class="tabs-content-inner">' +
'</div></div>' +
'</div>' ;
var DEFAULT _NAV =
'<li ng:class="currentCls(\'git-mac\')"><a ng:click="select(\'git-mac\')" href>Git on Mac/Linux</a></li>' +
'<li ng:class="currentCls(\'git-win\')"><a ng:click="select(\'git-win\')" href>Git on Windows</a></li>' +
'<li ng:class="currentCls(\'ss-mac\')"><a ng:click="select(\'ss-mac\')" href>Snapshots on Mac/Linux</a></li>' +
'<li ng:class="currentCls(\'ss-win\')"><a ng:click="select(\'ss-win\')" href>Snapshots on Windows</a></li>' ;
var DEFAULT _CONTENT =
'<div ng:show="selected==\'git-mac\'">' +
'<ol>' +
'<li><p>Reset the workspace to step {step}.</p>' +
'<pre><code> git checkout -f step-{step}</code></pre></li>' +
'<li><p>Refresh your browser or check the app out on <a href="http://angular.github.com/angular-phonecat/step-{step}/app">angular\'s server</a>.</p></li>' +
'</ol>' +
'</div>' +
'<div ng:show="selected==\'git-win\'">' +
'<ol>' +
'<li><p>Reset the workspace to step {step}.</p>' +
'<pre><code> git checkout -f step-{step}</code></pre></li>' +
'<li><p>Refresh your browser or check the app out on <a href="http://angular.github.com/angular-phonecat/step-{step}/app">angular\'s server</a>.</p></li>' +
'</ol>' +
'</div>' +
'<div ng:show="selected==\'ss-mac\'">' +
'<ol>' +
'<li><p>Reset the workspace to step {step}.</p>' +
'<pre><code> ./goto_step.sh {step}</code></pre></li>' +
'<li><p>Refresh your browser or check the app out on <a href="http://angular.github.com/angular-phonecat/step-{step}/app">angular\'s server</a>.</p></li>' +
'</ol>' +
'</div>' +
'<div ng:show="selected==\'ss-win\'">' +
'<ol>' +
'<li><p>Reset the workspace to step {step}.</p>' +
'<pre><code> ./goto_step.bat {step}</code></pre></li>' +
'<li><p>Refresh your browser or check the app out on <a href="http://angular.github.com/angular-phonecat/step-{step}/app">angular\'s server</a>.</p></li>' +
'</ol>' +
2011-05-23 22:49:33 +00:00
'</div>' ;
2011-11-23 05:28:39 +00:00
return {
compile : function ( element , attrs ) {
var tabs = angular . element ( HTML _TPL . replace ( '{show}' , attrs . show || 'false' ) ) ,
nav = tabs . find ( 'ul' ) ,
// use simple selectors because jqLite find() supports getElementsByTagName only
content = tabs . find ( 'div' ) . find ( 'div' ) ,
children = element . children ( ) ;
if ( children . length ) {
// load custom content
angular . forEach ( element . children ( ) , function ( elm ) {
elm = angular . element ( elm ) ;
var id = elm . attr ( 'id' ) ;
nav . append ( HTML _NAV . replace ( '{title}' , elm . attr ( 'title' ) ) . replace ( /\{id\}/g , id ) ) ;
content . append ( HTML _CONTENT . replace ( '{id}' , id ) . replace ( '{content}' , elm . html ( ) ) ) ;
} ) ;
} else {
// default
nav . append ( DEFAULT _NAV ) ;
content . append ( DEFAULT _CONTENT . replace ( /\{step\}/g , element . attr ( 'step' ) ) ) ;
}
2011-05-23 22:49:33 +00:00
2011-11-23 05:28:39 +00:00
element . html ( '' ) ;
element . append ( tabs ) ;
}
}
2011-05-23 22:49:33 +00:00
} ) ;
2011-06-06 15:52:02 +00:00
2011-11-23 05:28:39 +00:00
$compileProvider . directive ( 'docTutorialNav' , function ( ) {
return function ( scope , element , attrs ) {
2011-06-06 15:52:02 +00:00
var prevStep , codeDiff , nextStep ,
2011-11-23 05:28:39 +00:00
content , step = attrs . docTutorialNav ;
2011-06-06 15:52:02 +00:00
step = parseInt ( step , 10 ) ;
if ( step === 0 ) {
prevStep = '' ;
nextStep = 'step_01' ;
codeDiff = 'step-0~7...step-0' ;
} else if ( step === 11 ) {
prevStep = 'step_10' ;
nextStep = 'the_end' ;
codeDiff = 'step-10...step-11' ;
} else {
2011-06-06 21:03:04 +00:00
prevStep = 'step_' + pad ( step - 1 ) ;
2011-06-06 15:52:02 +00:00
nextStep = 'step_' + pad ( step + 1 ) ;
codeDiff = 'step-' + step + '...step-' + step ;
}
content = angular . element (
2011-06-07 00:21:45 +00:00
'<li><a href="#!/tutorial/' + prevStep + '">Previous</a></li>' +
2011-06-06 15:52:02 +00:00
'<li><a href="http://angular.github.com/angular-phonecat/step-' + step + '/app">Live Demo</a></li>' +
'<li><a href="https://github.com/angular/angular-phonecat/compare/' + codeDiff + '">Code Diff</a></li>' +
2011-06-07 00:21:45 +00:00
'<li><a href="#!/tutorial/' + nextStep + '">Next</a></li>'
2011-06-06 15:52:02 +00:00
) ;
element . attr ( 'id' , 'tutorial-nav' ) ;
element . append ( content ) ;
2011-06-06 21:03:04 +00:00
} ;
2011-06-06 15:52:02 +00:00
function pad ( step ) {
return ( step < 10 ) ? ( '0' + step ) : step ;
}
} ) ;
2011-11-23 05:28:39 +00:00
} ) ;