├── .bowerrc ├── .editorconfig ├── .gitignore ├── LICENSE ├── Procfile ├── README.md ├── bower.json ├── config.xml ├── docs └── images │ ├── doc_1.png │ ├── doc_2.png │ └── doc_3.png ├── gulpfile.js ├── hooks ├── README.md ├── after_prepare │ ├── 010_add_platform_class.js │ ├── 020_remove_sass_from_platforms.js │ ├── 030_clean_dev_files_from_platforms.js │ ├── 040_move_dist_files_to_platforms.js │ └── 050_clean_obfuscation.js └── before_prepare │ └── 01_jshint.js ├── ionic.project ├── package.json ├── platforms ├── ios │ ├── .gitignore │ ├── Ruby China.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcuserdata │ │ │ │ └── jason.xcuserdatad │ │ │ │ └── UserInterfaceState.xcuserstate │ │ └── xcuserdata │ │ │ └── jason.xcuserdatad │ │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ │ └── xcschemes │ │ │ ├── Ruby China.xcscheme │ │ │ └── xcschememanagement.plist │ ├── Ruby China │ │ ├── .gitignore │ │ ├── Bridging-Header.h │ │ ├── Classes │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── MainViewController.h │ │ │ ├── MainViewController.m │ │ │ └── MainViewController.xib │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── icon-40.png │ │ │ │ ├── icon-40@2x.png │ │ │ │ ├── icon-50.png │ │ │ │ ├── icon-50@2x.png │ │ │ │ ├── icon-60.png │ │ │ │ ├── icon-60@2x.png │ │ │ │ ├── icon-60@3x.png │ │ │ │ ├── icon-72.png │ │ │ │ ├── icon-72@2x.png │ │ │ │ ├── icon-76.png │ │ │ │ ├── icon-76@2x.png │ │ │ │ ├── icon-83.5@2x.png │ │ │ │ ├── icon-small.png │ │ │ │ ├── icon-small@2x.png │ │ │ │ ├── icon-small@3x.png │ │ │ │ ├── icon.png │ │ │ │ └── icon@2x.png │ │ │ └── LaunchImage.launchimage │ │ │ │ ├── Contents.json │ │ │ │ ├── Default-568h@2x~iphone.png │ │ │ │ ├── Default-667h.png │ │ │ │ ├── Default-736h.png │ │ │ │ ├── Default-Landscape-736h.png │ │ │ │ ├── Default-Landscape@2x~ipad.png │ │ │ │ ├── Default-Landscape~ipad.png │ │ │ │ ├── Default-Portrait@2x~ipad.png │ │ │ │ ├── Default-Portrait~ipad.png │ │ │ │ ├── Default@2x~iphone.png │ │ │ │ └── Default~iphone.png │ │ ├── Ruby China-Info.plist │ │ ├── Ruby China-Prefix.pch │ │ ├── config.xml │ │ └── main.m │ ├── frameworks.json │ └── ios.json └── platforms.json ├── resources ├── android │ ├── icon │ │ ├── drawable-hdpi-icon.png │ │ ├── drawable-ldpi-icon.png │ │ ├── drawable-mdpi-icon.png │ │ ├── drawable-xhdpi-icon.png │ │ ├── drawable-xxhdpi-icon.png │ │ └── drawable-xxxhdpi-icon.png │ └── splash │ │ ├── drawable-land-hdpi-screen.png │ │ ├── drawable-land-ldpi-screen.png │ │ ├── drawable-land-mdpi-screen.png │ │ ├── drawable-land-xhdpi-screen.png │ │ ├── drawable-land-xxhdpi-screen.png │ │ ├── drawable-land-xxxhdpi-screen.png │ │ ├── drawable-port-hdpi-screen.png │ │ ├── drawable-port-ldpi-screen.png │ │ ├── drawable-port-mdpi-screen.png │ │ ├── drawable-port-xhdpi-screen.png │ │ ├── drawable-port-xxhdpi-screen.png │ │ └── drawable-port-xxxhdpi-screen.png ├── icon.png ├── icon_trans.png ├── ios │ ├── icon │ │ ├── icon-40.png │ │ ├── icon-40@2x.png │ │ ├── icon-50.png │ │ ├── icon-50@2x.png │ │ ├── icon-60.png │ │ ├── icon-60@2x.png │ │ ├── icon-60@3x.png │ │ ├── icon-72.png │ │ ├── icon-72@2x.png │ │ ├── icon-76.png │ │ ├── icon-76@2x.png │ │ ├── icon-small.png │ │ ├── icon-small@2x.png │ │ ├── icon-small@3x.png │ │ ├── icon.png │ │ └── icon@2x.png │ └── splash │ │ ├── Default-568h@2x~iphone.png │ │ ├── Default-667h.png │ │ ├── Default-736h.png │ │ ├── Default-Landscape-736h.png │ │ ├── Default-Landscape@2x~ipad.png │ │ ├── Default-Landscape~ipad.png │ │ ├── Default-Portrait@2x~ipad.png │ │ ├── Default-Portrait~ipad.png │ │ ├── Default@2x~iphone.png │ │ └── Default~iphone.png └── splash.png ├── scss ├── _base.scss ├── _markdown.scss ├── _menu.scss ├── _notifications.scss ├── _topic.scss ├── _topics.scss ├── _user.scss └── style.scss └── www ├── img ├── default_avatar.png └── ionic.png ├── index.html ├── js ├── app.js ├── controllers │ ├── controller.module.js │ ├── main.controller.js │ ├── notifications.controller.js │ ├── topic.controller.js │ ├── topics.controller.js │ └── user.controller.js ├── core │ ├── config.core.js │ ├── core.module.js │ ├── route.core.js │ └── run.core.js ├── filters │ ├── exlink.filter.js │ └── filter.module.js └── services │ ├── auth.service.js │ ├── base.service.js │ ├── camera.service.js │ ├── service.module.js │ ├── topic.service.js │ └── user.service.js └── templates ├── menu.html ├── modals ├── code_selector.html ├── login.html ├── new_topic.html └── reply.html ├── notifications.html ├── notifications ├── follow.html ├── mention.html ├── nodechanged.html ├── topic.html └── topicreply.html ├── topic.html ├── topics.html └── user └── profile.html /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "www/lib" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | insert_final_newline = false 14 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Specifies intentionally untracked files to ignore when using Git 2 | # http://git-scm.com/docs/gitignore 3 | 4 | node_modules/ 5 | platforms/ios/build 6 | platforms/ios/cordova 7 | platforms/ios/CordovaLib 8 | platforms/ios/www 9 | platforms/ios/platform_www 10 | plugins/ 11 | .idea 12 | .temp 13 | .sass-cache 14 | *.swp 15 | *.swo 16 | *.log 17 | *.DS_Store 18 | www/lib 19 | www/dist/** 20 | www/css 21 | www/annotated_js/** 22 | npm-debug.log 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ruby China 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | ionic: ionic serve -w chrome -a -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ruby China App 2 | Official Ruby China Mobile App for iOS and Android using Ionic framework. 3 | 4 | [![Download on the app store](https://devimages.apple.com.edgekey.net/app-store/marketing/guidelines/images/badge-download-on-the-app-store.svg)](https://itunes.apple.com/cn/app/ruby-china-guan-fang-ke-hu-duan/id1072028763?mt=8) 5 | 6 | 🚀 **An refactor version according to Johnpapa's AngularJS Style, and redraw UI with Material elements** 7 | ⏳ **Additional, adding Gulp make it easy to build** 8 | 🚿 **New UI + New DE make it more fun to play Front-end Development** 9 | 10 | ## The 1st Major Release (Progress) 11 | 1. User Login / Logout(100%) 12 | 2. Topic List(100%) 13 | 3. Topic Detail(100%) 14 | 4. New Topic(100%) 15 | 5. Reply(100%) 16 | 6. HomePage(100%) 17 | 7. Profile(0%) 18 | 8. My Topics(0%) 19 | 9. My Favorites(0%) 20 | 10. Push Notification(80%) 21 | 11. Settings(0%) 22 | 23 | ## Installation 24 | It really need NodeJS & Ionic installed before you can play Our Project 25 | 26 | * NodeJS following:[Install NodeJS](https://nodejs.org/en/) 27 | * Ionic following:[Install Ionic](http://ionicframework.com/getting-started/) 28 | 29 | ```bash 30 | # Enter project root folder and input: 31 | $ npm install && bower install 32 | 33 | # auto-generater dist/ folder 34 | $ gulp useref 35 | 36 | # Adding iOS Platform 37 | $ ionic platform add ios 38 | 39 | # Adding Android Platform 40 | $ ionic platform add android 41 | ``` 42 | 43 | ## Development 44 | Use `$ foreman start` or `$ ionic serve -w chrome -a` to start Server 45 | > cannot run foreman? run `$ gem install foreman` first. 46 | 47 | Use `bower install *** --save` install Bower components 48 | > If the dev server is running,Gulp will help you to adding all js dependency to `index.html` 49 | > If not, run `$ gulp` to make it. 50 | 51 | Use `npm install *** --save-dev` install npm modules 52 | 53 | 54 | ## Run in Chrome 55 | 56 | Open your Chrome and locate: http://localhost:8100/ 57 | > Select device what you like 58 | 59 | ##### Screenshots 60 | ![](docs/images/doc_1.png) 61 | 62 | ## Run in Xcode 63 | Following these step, and you'll see it. 64 | 65 | ```bash 66 | # 1. Adding iOS Support 67 | $ ionic platform add ios 68 | 69 | # 2. Building 70 | $ ionic build ios 71 | 72 | # 3. run it in your simulator 73 | $ ionic emulate ios 74 | # another way, open Xcode first then run. 75 | $ open platforms/ios/Ruby China App.xcodeproj 76 | ``` 77 | 78 | ##### Screenshots 79 | ![](docs/images/doc_2.png) 80 | 81 | ## Run in Android 82 | Following these step, and you'll see it. 83 | 84 | ```bash 85 | # 1. Adding Android Support 86 | $ ionic platform add android 87 | 88 | # 2. Download Android SDK & Simulator first 89 | > Ref on Mac[Android Studio Installation](http://developer.android.com/sdk/installing/index.html?pkg=studio) 90 | 91 | # 3. Everythings ok then build it 92 | $ ionic build android 93 | 94 | # 4. Open your simulator 95 | $ ionic emulate android 96 | ``` 97 | 98 | ##### Screenshots 99 | ![](docs/images/doc_3.png) 100 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ruby-china-app", 3 | "private": "true", 4 | "devDependencies": { 5 | "ionic": "~1.2.1" 6 | }, 7 | "dependencies": { 8 | "angular-moment": "~0.10.3", 9 | "angular-oauth2": "~3.0.1", 10 | "ng-file-upload": "~10.0.2", 11 | "robotodraft": "~1.1.0", 12 | "mdi": "~1.3.41", 13 | "lodash": "~3.10.1", 14 | "ngCordova": "~0.1.23-alpha" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ruby China 4 | 5 | Official Ruby China Mobile App for iOS and Android. 6 | 7 | 8 | Ruby China Team 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /docs/images/doc_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/docs/images/doc_1.png -------------------------------------------------------------------------------- /docs/images/doc_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/docs/images/doc_2.png -------------------------------------------------------------------------------- /docs/images/doc_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/docs/images/doc_3.png -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var sh = require('shelljs'); 3 | var bower = require('bower'); 4 | var args = require('yargs').argv; 5 | var gulpif = require('gulp-if'); 6 | var bower = require('./bower.json'); 7 | var $ = require('gulp-load-plugins')({ 8 | lazy: true 9 | }); 10 | 11 | var paths = { 12 | lib: './www/lib', 13 | sass: ['./scss/**/*.scss'], 14 | src_js: ['./www/js/{,*/}*.module.js', './www/js/{,*/}*.js'], 15 | annotated_js: ['./www/annotated_js/{,*/}*.module.js', './www/annotated_js/{,*/}*.js'], 16 | templates: ['./www/templates/{,*/}*.html'], 17 | index: './www/index.html', 18 | useref: ['./www/*.html'], 19 | dist: ['./www/dist/**'] 20 | }; 21 | 22 | gulp.task('default', ['sass', 'wiredep']); 23 | 24 | gulp.task('sass', function(done) { 25 | gulp.src('./scss/style.scss') 26 | .pipe($.sass()) 27 | .on('error', $.sass.logError) 28 | .pipe(gulp.dest('./www/css/')) 29 | .pipe($.minifyCss({ 30 | keepSpecialComments: 0 31 | })) 32 | .pipe($.rename({ 33 | extname: '.min.css' 34 | })) 35 | .pipe(gulp.dest('./www/css/')) 36 | .on('end', done); 37 | }); 38 | 39 | gulp.task('watch', function() { 40 | gulp.watch(paths.sass, ['sass']); 41 | gulp.watch(paths.templates, ['templateCache']); 42 | gulp.watch(paths.src_js, ['wiredep']); 43 | }); 44 | 45 | gulp.task('install', ['git-check'], function() { 46 | return bower.commands.install() 47 | .on('log', function(data) { 48 | gutil.log('bower', gutil.colors.cyan(data.id), data.message); 49 | }); 50 | }); 51 | 52 | gulp.task('git-check', function(done) { 53 | if (!sh.which('git')) { 54 | console.log( 55 | ' ' + gutil.colors.red('Git is not installed.'), 56 | '\n Git, the version control system, is required to download Ionic.', 57 | '\n Download git here:', gutil.colors.cyan('http://git-scm.com/downloads') + '.', 58 | '\n Once git is installed, run \'' + gutil.colors.cyan('gulp install') + '\' again.' 59 | ); 60 | process.exit(1); 61 | } 62 | done(); 63 | }); 64 | 65 | gulp.task('templateCache', function() { 66 | return gulp.src(paths.templates) 67 | .pipe($.angularTemplatecache({ 68 | standalone: true 69 | })) 70 | .pipe(gulp.dest('./www/annotated_js')); 71 | }); 72 | 73 | gulp.task('clean-dist', function() { 74 | return gulp 75 | .src(paths.dist, { 76 | read: false 77 | }) 78 | .pipe($.rimraf()); 79 | }); 80 | 81 | // 增加依赖注入 82 | gulp.task('ngAnnotate', ['templateCache'], function() { 83 | return gulp.src(paths.src_js) 84 | .pipe($.ngAnnotate({ 85 | single_quotes: true 86 | })) 87 | .pipe(gulp.dest('./www/annotated_js')); 88 | }); 89 | 90 | // 将所有JS及CSS引用添加到index.html 91 | gulp.task('wiredep', ['ngAnnotate'], function() { 92 | var options = { 93 | bowerJson: bower, 94 | directory: paths.lib, 95 | ignorePath: '../..', 96 | devDependencies: true 97 | }; 98 | var wiredep = require('wiredep').stream; 99 | 100 | return gulp 101 | .src(paths.index) 102 | .pipe(wiredep(options)) 103 | .pipe($.inject(gulp.src(paths.annotated_js, { 104 | read: false 105 | }), { 106 | relative: true 107 | })) 108 | .pipe(gulp.dest('./www')); 109 | }); 110 | 111 | 112 | gulp.task('useref', ['clean-dist', 'sass', 'wiredep'], function() { 113 | return gulp.src(paths.useref) 114 | .pipe($.useref()) 115 | .pipe(gulpif('*.js', $.uglify())) 116 | .pipe(gulpif('*.css', $.minifyCss())) 117 | .pipe(gulp.dest('./www/dist')); 118 | }); 119 | -------------------------------------------------------------------------------- /hooks/README.md: -------------------------------------------------------------------------------- 1 | 21 | # Cordova Hooks 22 | 23 | This directory may contain scripts used to customize cordova commands. This 24 | directory used to exist at `.cordova/hooks`, but has now been moved to the 25 | project root. Any scripts you add to these directories will be executed before 26 | and after the commands corresponding to the directory name. Useful for 27 | integrating your own build systems or integrating with version control systems. 28 | 29 | __Remember__: Make your scripts executable. 30 | 31 | ## Hook Directories 32 | The following subdirectories will be used for hooks: 33 | 34 | after_build/ 35 | after_compile/ 36 | after_docs/ 37 | after_emulate/ 38 | after_platform_add/ 39 | after_platform_rm/ 40 | after_platform_ls/ 41 | after_plugin_add/ 42 | after_plugin_ls/ 43 | after_plugin_rm/ 44 | after_plugin_search/ 45 | after_prepare/ 46 | after_run/ 47 | after_serve/ 48 | before_build/ 49 | before_compile/ 50 | before_docs/ 51 | before_emulate/ 52 | before_platform_add/ 53 | before_platform_rm/ 54 | before_platform_ls/ 55 | before_plugin_add/ 56 | before_plugin_ls/ 57 | before_plugin_rm/ 58 | before_plugin_search/ 59 | before_prepare/ 60 | before_run/ 61 | before_serve/ 62 | pre_package/ <-- Windows 8 and Windows Phone only. 63 | 64 | ## Script Interface 65 | 66 | All scripts are run from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables: 67 | 68 | * CORDOVA_VERSION - The version of the Cordova-CLI. 69 | * CORDOVA_PLATFORMS - Comma separated list of platforms that the command applies to (e.g.: android, ios). 70 | * CORDOVA_PLUGINS - Comma separated list of plugin IDs that the command applies to (e.g.: org.apache.cordova.file, org.apache.cordova.file-transfer) 71 | * CORDOVA_HOOK - Path to the hook that is being executed. 72 | * CORDOVA_CMDLINE - The exact command-line arguments passed to cordova (e.g.: cordova run ios --emulate) 73 | 74 | If a script returns a non-zero exit code, then the parent cordova command will be aborted. 75 | 76 | 77 | ## Writing hooks 78 | 79 | We highly recommend writting your hooks using Node.js so that they are 80 | cross-platform. Some good examples are shown here: 81 | 82 | [http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/](http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/) 83 | 84 | -------------------------------------------------------------------------------- /hooks/after_prepare/010_add_platform_class.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // Add Platform Class 4 | // v1.0 5 | // Automatically adds the platform class to the body tag 6 | // after the `prepare` command. By placing the platform CSS classes 7 | // directly in the HTML built for the platform, it speeds up 8 | // rendering the correct layout/style for the specific platform 9 | // instead of waiting for the JS to figure out the correct classes. 10 | 11 | var fs = require('fs'); 12 | var path = require('path'); 13 | 14 | var rootdir = process.argv[2]; 15 | 16 | function addPlatformBodyTag(indexPath, platform) { 17 | // add the platform class to the body tag 18 | try { 19 | var platformClass = 'platform-' + platform; 20 | var cordovaClass = 'platform-cordova platform-webview'; 21 | 22 | var html = fs.readFileSync(indexPath, 'utf8'); 23 | 24 | var bodyTag = findBodyTag(html); 25 | if(!bodyTag) return; // no opening body tag, something's wrong 26 | 27 | if(bodyTag.indexOf(platformClass) > -1) return; // already added 28 | 29 | var newBodyTag = bodyTag; 30 | 31 | var classAttr = findClassAttr(bodyTag); 32 | if(classAttr) { 33 | // body tag has existing class attribute, add the classname 34 | var endingQuote = classAttr.substring(classAttr.length-1); 35 | var newClassAttr = classAttr.substring(0, classAttr.length-1); 36 | newClassAttr += ' ' + platformClass + ' ' + cordovaClass + endingQuote; 37 | newBodyTag = bodyTag.replace(classAttr, newClassAttr); 38 | 39 | } else { 40 | // add class attribute to the body tag 41 | newBodyTag = bodyTag.replace('>', ' class="' + platformClass + ' ' + cordovaClass + '">'); 42 | } 43 | 44 | html = html.replace(bodyTag, newBodyTag); 45 | 46 | fs.writeFileSync(indexPath, html, 'utf8'); 47 | 48 | process.stdout.write('add to body class: ' + platformClass + '\n'); 49 | } catch(e) { 50 | process.stdout.write(e); 51 | } 52 | } 53 | 54 | function findBodyTag(html) { 55 | // get the body tag 56 | try{ 57 | return html.match(/])(.*?)>/gi)[0]; 58 | }catch(e){} 59 | } 60 | 61 | function findClassAttr(bodyTag) { 62 | // get the body tag's class attribute 63 | try{ 64 | return bodyTag.match(/ class=["|'](.*?)["|']/gi)[0]; 65 | }catch(e){} 66 | } 67 | 68 | if (rootdir) { 69 | 70 | // go through each of the platform directories that have been prepared 71 | var platforms = (process.env.CORDOVA_PLATFORMS ? process.env.CORDOVA_PLATFORMS.split(',') : []); 72 | 73 | for(var x=0; x 0) { 43 | process.exit(1); 44 | } 45 | }); 46 | }); 47 | } 48 | 49 | function lintFile(file, callback) { 50 | console.log("Linting " + file); 51 | fs.readFile(file, function(err, data) { 52 | if (err) { 53 | console.log('Error: ' + err); 54 | return; 55 | } 56 | if (jshint(data.toString())) { 57 | console.log('File ' + file + ' has no errors.'); 58 | console.log('-----------------------------------------'); 59 | callback(false); 60 | } else { 61 | console.log('Errors in file ' + file); 62 | var out = jshint.data(), 63 | errors = out.errors; 64 | for (var j = 0; j < errors.length; j++) { 65 | console.log(errors[j].line + ':' + errors[j].character + ' -> ' + errors[j].reason + ' -> ' + 66 | errors[j].evidence); 67 | } 68 | console.log('-----------------------------------------'); 69 | callback(true); 70 | } 71 | }); 72 | } 73 | -------------------------------------------------------------------------------- /ionic.project: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RubyChina App", 3 | "app_id": "61fdad52", 4 | "gulpStartupTasks": [ 5 | "wiredep", 6 | "watch", 7 | "sass" 8 | ], 9 | "watchPatterns": [ 10 | "www/**/*", 11 | "!www/lib/**/*" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ruby-china-app", 3 | "description": "Official Ruby China Mobile App", 4 | "dependencies": {}, 5 | "devDependencies": { 6 | "async": "^1.5.0", 7 | "bower": "^1.3.3", 8 | "clean-css": "^3.4.8", 9 | "gulp": "^3.5.6", 10 | "gulp-angular-templatecache": "^1.8.0", 11 | "gulp-concat": "^2.2.0", 12 | "gulp-if": "^2.0.0", 13 | "gulp-inject": "^3.0.0", 14 | "gulp-load-plugins": "^1.1.0", 15 | "gulp-minify-css": "^1.2.3", 16 | "gulp-ng-annotate": "^1.1.0", 17 | "gulp-print": "^2.0.1", 18 | "gulp-rename": "^1.2.0", 19 | "gulp-rimraf": "^0.2.0", 20 | "gulp-sass": "^2.0.4", 21 | "gulp-uglify": "^1.5.1", 22 | "gulp-useref": "^3.0.0", 23 | "gulp-util": "^3.0.7", 24 | "ionic": "1.7.14", 25 | "jshint": "^2.8.0", 26 | "jshint-stylish": "^2.1.0", 27 | "mv": "^2.1.1", 28 | "ng-annotate": "^1.0.2", 29 | "shelljs": "^0.5.3", 30 | "uglify-js": "^2.6.1", 31 | "wiredep": "3.0.0", 32 | "yargs": "^3.30.0" 33 | }, 34 | "cordovaPlugins": [ 35 | "cordova-plugin-safariviewcontroller", 36 | "cordova-plugin-app-version", 37 | "cordova-plugin-statusbar", 38 | "cordova-plugin-device", 39 | "cordova-plugin-whitelist", 40 | { 41 | "locator": "https://github.com/phonegap-build/PushPlugin", 42 | "id": "phonegap-plugin-push", 43 | "tag": "2.5.0" 44 | } 45 | ], 46 | "cordovaPlatforms": [ 47 | "ios" 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /platforms/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.perspectivev3 3 | *.pbxuser 4 | .DS_Store 5 | build/ 6 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China.xcodeproj/project.xcworkspace/xcuserdata/jason.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China.xcodeproj/project.xcworkspace/xcuserdata/jason.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /platforms/ios/Ruby China.xcodeproj/xcuserdata/jason.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China.xcodeproj/xcuserdata/jason.xcuserdatad/xcschemes/Ruby China.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China.xcodeproj/xcuserdata/jason.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Ruby China.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 1D6058900D05DD3D006BFB54 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.perspectivev3 3 | *.pbxuser 4 | .DS_Store 5 | build/ 6 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Bridging-Header.h: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | Unless required by applicable law or agreed to in writing, 11 | software distributed under the License is distributed on an 12 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | KIND, either express or implied. See the License for the 14 | specific language governing permissions and limitations 15 | under the License. 16 | */ 17 | // 18 | // Bridging-Header.h 19 | // __PROJECT_NAME__ 20 | // 21 | // Created by ___FULLUSERNAME___ on ___DATE___. 22 | // Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved. 23 | // 24 | // 25 | // Use this file to import your target's public headers that you would like to expose to Swift. 26 | // 27 | 28 | #import 29 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Classes/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | // 21 | // AppDelegate.h 22 | // Ruby China 23 | // 24 | // Created by ___FULLUSERNAME___ on ___DATE___. 25 | // Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved. 26 | // 27 | 28 | #import 29 | #import 30 | 31 | @interface AppDelegate : CDVAppDelegate {} 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Classes/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | // 21 | // AppDelegate.m 22 | // Ruby China 23 | // 24 | // Created by ___FULLUSERNAME___ on ___DATE___. 25 | // Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved. 26 | // 27 | 28 | #import "AppDelegate.h" 29 | #import "MainViewController.h" 30 | 31 | @implementation AppDelegate 32 | 33 | - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions 34 | { 35 | self.viewController = [[MainViewController alloc] init]; 36 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Classes/MainViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | // 21 | // MainViewController.h 22 | // Ruby China 23 | // 24 | // Created by ___FULLUSERNAME___ on ___DATE___. 25 | // Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved. 26 | // 27 | 28 | #import 29 | #import 30 | #import 31 | 32 | @interface MainViewController : CDVViewController 33 | 34 | @end 35 | 36 | @interface MainCommandDelegate : CDVCommandDelegateImpl 37 | @end 38 | 39 | @interface MainCommandQueue : CDVCommandQueue 40 | @end 41 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Classes/MainViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | // 21 | // MainViewController.h 22 | // Ruby China 23 | // 24 | // Created by ___FULLUSERNAME___ on ___DATE___. 25 | // Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved. 26 | // 27 | 28 | #import "MainViewController.h" 29 | 30 | @implementation MainViewController 31 | 32 | - (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil 33 | { 34 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 35 | if (self) { 36 | // Uncomment to override the CDVCommandDelegateImpl used 37 | // _commandDelegate = [[MainCommandDelegate alloc] initWithViewController:self]; 38 | // Uncomment to override the CDVCommandQueue used 39 | // _commandQueue = [[MainCommandQueue alloc] initWithViewController:self]; 40 | } 41 | return self; 42 | } 43 | 44 | - (id)init 45 | { 46 | self = [super init]; 47 | if (self) { 48 | // Uncomment to override the CDVCommandDelegateImpl used 49 | // _commandDelegate = [[MainCommandDelegate alloc] initWithViewController:self]; 50 | // Uncomment to override the CDVCommandQueue used 51 | // _commandQueue = [[MainCommandQueue alloc] initWithViewController:self]; 52 | } 53 | return self; 54 | } 55 | 56 | - (void)didReceiveMemoryWarning 57 | { 58 | // Releases the view if it doesn't have a superview. 59 | [super didReceiveMemoryWarning]; 60 | 61 | // Release any cached data, images, etc that aren't in use. 62 | } 63 | 64 | #pragma mark View lifecycle 65 | 66 | - (void)viewWillAppear:(BOOL)animated 67 | { 68 | // View defaults to full size. If you want to customize the view's size, or its subviews (e.g. webView), 69 | // you can do so here. 70 | 71 | [super viewWillAppear:animated]; 72 | } 73 | 74 | - (void)viewDidLoad 75 | { 76 | [super viewDidLoad]; 77 | // Do any additional setup after loading the view from its nib. 78 | } 79 | 80 | - (void)viewDidUnload 81 | { 82 | [super viewDidUnload]; 83 | // Release any retained subviews of the main view. 84 | // e.g. self.myOutlet = nil; 85 | } 86 | 87 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 88 | { 89 | // Return YES for supported orientations 90 | return [super shouldAutorotateToInterfaceOrientation:interfaceOrientation]; 91 | } 92 | 93 | /* Comment out the block below to over-ride */ 94 | 95 | /* 96 | - (UIWebView*) newCordovaViewWithFrame:(CGRect)bounds 97 | { 98 | return[super newCordovaViewWithFrame:bounds]; 99 | } 100 | */ 101 | 102 | @end 103 | 104 | @implementation MainCommandDelegate 105 | 106 | /* To override the methods, uncomment the line in the init function(s) 107 | in MainViewController.m 108 | */ 109 | 110 | #pragma mark CDVCommandDelegate implementation 111 | 112 | - (id)getCommandInstance:(NSString*)className 113 | { 114 | return [super getCommandInstance:className]; 115 | } 116 | 117 | - (NSString*)pathForResource:(NSString*)resourcepath 118 | { 119 | return [super pathForResource:resourcepath]; 120 | } 121 | 122 | @end 123 | 124 | @implementation MainCommandQueue 125 | 126 | /* To override, uncomment the line in the init function(s) 127 | in MainViewController.m 128 | */ 129 | - (BOOL)execute:(CDVInvokedUrlCommand*)command 130 | { 131 | return [super execute:command]; 132 | } 133 | 134 | @end 135 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Classes/MainViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 22 | 23 | 24 | 1280 25 | 11C25 26 | 1919 27 | 1138.11 28 | 566.00 29 | 30 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 31 | 916 32 | 33 | 34 | IBProxyObject 35 | IBUIView 36 | 37 | 38 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 39 | 40 | 41 | PluginDependencyRecalculationVersion 42 | 43 | 44 | 45 | 46 | IBFilesOwner 47 | IBCocoaTouchFramework 48 | 49 | 50 | IBFirstResponder 51 | IBCocoaTouchFramework 52 | 53 | 54 | 55 | 274 56 | {{0, 20}, {320, 460}} 57 | 58 | 59 | 60 | 3 61 | MQA 62 | 63 | 2 64 | 65 | 66 | 67 | IBCocoaTouchFramework 68 | 69 | 70 | 71 | 72 | 73 | 74 | view 75 | 76 | 77 | 78 | 3 79 | 80 | 81 | 82 | 83 | 84 | 0 85 | 86 | 87 | 88 | 89 | 90 | 1 91 | 92 | 93 | 94 | 95 | -1 96 | 97 | 98 | File's Owner 99 | 100 | 101 | -2 102 | 103 | 104 | 105 | 106 | 107 | 108 | MainViewController 109 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 110 | UIResponder 111 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 112 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 113 | 114 | 115 | 116 | 117 | 118 | 3 119 | 120 | 121 | 122 | 123 | MainViewController 124 | UIViewController 125 | 126 | IBProjectSource 127 | ./Classes/MainViewController.h 128 | 129 | 130 | 131 | 132 | 0 133 | IBCocoaTouchFramework 134 | YES 135 | 3 136 | 916 137 | 138 | 139 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "filename" : "icon-small.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "idiom" : "iphone", 11 | "size" : "29x29", 12 | "filename" : "icon-small@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "idiom" : "iphone", 17 | "size" : "29x29", 18 | "filename" : "icon-small@3x.png", 19 | "scale" : "3x" 20 | }, 21 | { 22 | "idiom" : "iphone", 23 | "size" : "40x40", 24 | "filename" : "icon-40@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "idiom" : "iphone", 29 | "size" : "40x40", 30 | "filename" : "icon-60@2x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "57x57", 36 | "filename" : "icon.png", 37 | "scale" : "1x" 38 | }, 39 | { 40 | "idiom" : "iphone", 41 | "size" : "57x57", 42 | "filename" : "icon@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "idiom" : "iphone", 47 | "size" : "60x60", 48 | "filename" : "icon-60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "idiom" : "iphone", 53 | "size" : "60x60", 54 | "filename" : "icon-60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "idiom" : "ipad", 59 | "size" : "29x29", 60 | "filename" : "icon-small.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "29x29", 66 | "filename" : "icon-small@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "idiom" : "ipad", 71 | "size" : "40x40", 72 | "filename" : "icon-40.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "idiom" : "ipad", 77 | "size" : "40x40", 78 | "filename" : "icon-40@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "idiom" : "ipad", 83 | "size" : "50x50", 84 | "filename" : "icon-50.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "idiom" : "ipad", 89 | "size" : "50x50", 90 | "filename" : "icon-50@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "idiom" : "ipad", 95 | "size" : "72x72", 96 | "filename" : "icon-72.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "idiom" : "ipad", 101 | "size" : "72x72", 102 | "filename" : "icon-72@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "idiom" : "ipad", 107 | "size" : "76x76", 108 | "filename" : "icon-76.png", 109 | "scale" : "1x" 110 | }, 111 | { 112 | "idiom" : "ipad", 113 | "size" : "76x76", 114 | "filename" : "icon-76@2x.png", 115 | "scale" : "2x" 116 | }, 117 | { 118 | "idiom" : "ipad", 119 | "size" : "83.5x83.5", 120 | "filename" : "icon-83.5@2x.png", 121 | "scale" : "2x" 122 | }, 123 | { 124 | "size" : "24x24", 125 | "idiom" : "watch", 126 | "scale" : "2x", 127 | "role" : "notificationCenter", 128 | "subtype" : "38mm" 129 | }, 130 | { 131 | "size" : "27.5x27.5", 132 | "idiom" : "watch", 133 | "scale" : "2x", 134 | "role" : "notificationCenter", 135 | "subtype" : "42mm" 136 | }, 137 | { 138 | "size" : "29x29", 139 | "idiom" : "watch", 140 | "role" : "companionSettings", 141 | "scale" : "2x" 142 | }, 143 | { 144 | "size" : "29x29", 145 | "idiom" : "watch", 146 | "role" : "companionSettings", 147 | "scale" : "3x" 148 | }, 149 | { 150 | "size" : "40x40", 151 | "idiom" : "watch", 152 | "scale" : "2x", 153 | "role" : "appLauncher", 154 | "subtype" : "38mm" 155 | }, 156 | { 157 | "size" : "44x44", 158 | "idiom" : "watch", 159 | "scale" : "2x", 160 | "role" : "longLook", 161 | "subtype" : "42mm" 162 | }, 163 | { 164 | "size" : "86x86", 165 | "idiom" : "watch", 166 | "scale" : "2x", 167 | "role" : "quickLook", 168 | "subtype" : "38mm" 169 | }, 170 | { 171 | "size" : "98x98", 172 | "idiom" : "watch", 173 | "scale" : "2x", 174 | "role" : "quickLook", 175 | "subtype" : "42mm" 176 | } 177 | ], 178 | "info" : { 179 | "version" : 1, 180 | "author" : "xcode" 181 | } 182 | } -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-40.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-40@2x.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-50.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-50@2x.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-60.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-60@2x.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-60@3x.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-72.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-72@2x.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-76.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-76@2x.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-83.5@2x.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-small.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-small@2x.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon-small@3x.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/AppIcon.appiconset/icon@2x.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "iphone", 6 | "subtype" : "736h", 7 | "filename" : "Default-736h.png", 8 | "minimum-system-version" : "8.0", 9 | "orientation" : "portrait", 10 | "scale" : "3x" 11 | }, 12 | { 13 | "extent" : "full-screen", 14 | "idiom" : "iphone", 15 | "subtype" : "736h", 16 | "filename" : "Default-Landscape-736h.png", 17 | "minimum-system-version" : "8.0", 18 | "orientation" : "landscape", 19 | "scale" : "3x" 20 | }, 21 | { 22 | "extent" : "full-screen", 23 | "idiom" : "iphone", 24 | "subtype" : "667h", 25 | "filename" : "Default-667h.png", 26 | "minimum-system-version" : "8.0", 27 | "orientation" : "portrait", 28 | "scale" : "2x" 29 | }, 30 | { 31 | "orientation" : "portrait", 32 | "idiom" : "iphone", 33 | "filename" : "Default@2x~iphone.png", 34 | "extent" : "full-screen", 35 | "minimum-system-version" : "7.0", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "extent" : "full-screen", 40 | "idiom" : "iphone", 41 | "subtype" : "retina4", 42 | "filename" : "Default-568h@2x~iphone.png", 43 | "minimum-system-version" : "7.0", 44 | "orientation" : "portrait", 45 | "scale" : "2x" 46 | }, 47 | { 48 | "orientation" : "portrait", 49 | "idiom" : "ipad", 50 | "filename" : "Default-Portrait~ipad.png", 51 | "extent" : "full-screen", 52 | "minimum-system-version" : "7.0", 53 | "scale" : "1x" 54 | }, 55 | { 56 | "orientation" : "landscape", 57 | "idiom" : "ipad", 58 | "filename" : "Default-Landscape~ipad.png", 59 | "extent" : "full-screen", 60 | "minimum-system-version" : "7.0", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "orientation" : "portrait", 65 | "idiom" : "ipad", 66 | "filename" : "Default-Portrait@2x~ipad.png", 67 | "extent" : "full-screen", 68 | "minimum-system-version" : "7.0", 69 | "scale" : "2x" 70 | }, 71 | { 72 | "orientation" : "landscape", 73 | "idiom" : "ipad", 74 | "filename" : "Default-Landscape@2x~ipad.png", 75 | "extent" : "full-screen", 76 | "minimum-system-version" : "7.0", 77 | "scale" : "2x" 78 | }, 79 | { 80 | "orientation" : "portrait", 81 | "idiom" : "iphone", 82 | "filename" : "Default~iphone.png", 83 | "extent" : "full-screen", 84 | "scale" : "1x" 85 | }, 86 | { 87 | "orientation" : "portrait", 88 | "idiom" : "iphone", 89 | "filename" : "Default@2x~iphone.png", 90 | "extent" : "full-screen", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "orientation" : "portrait", 95 | "idiom" : "iphone", 96 | "filename" : "Default-568h@2x~iphone.png", 97 | "extent" : "full-screen", 98 | "subtype" : "retina4", 99 | "scale" : "2x" 100 | }, 101 | { 102 | "orientation" : "portrait", 103 | "idiom" : "ipad", 104 | "extent" : "to-status-bar", 105 | "scale" : "1x" 106 | }, 107 | { 108 | "orientation" : "portrait", 109 | "idiom" : "ipad", 110 | "filename" : "Default-Portrait~ipad.png", 111 | "extent" : "full-screen", 112 | "scale" : "1x" 113 | }, 114 | { 115 | "orientation" : "landscape", 116 | "idiom" : "ipad", 117 | "extent" : "to-status-bar", 118 | "scale" : "1x" 119 | }, 120 | { 121 | "orientation" : "landscape", 122 | "idiom" : "ipad", 123 | "extent" : "full-screen", 124 | "scale" : "1x" 125 | }, 126 | { 127 | "orientation" : "portrait", 128 | "idiom" : "ipad", 129 | "extent" : "to-status-bar", 130 | "scale" : "2x" 131 | }, 132 | { 133 | "orientation" : "portrait", 134 | "idiom" : "ipad", 135 | "filename" : "Default-Portrait@2x~ipad.png", 136 | "extent" : "full-screen", 137 | "scale" : "2x" 138 | }, 139 | { 140 | "orientation" : "landscape", 141 | "idiom" : "ipad", 142 | "extent" : "to-status-bar", 143 | "scale" : "2x" 144 | }, 145 | { 146 | "orientation" : "landscape", 147 | "idiom" : "ipad", 148 | "extent" : "full-screen", 149 | "scale" : "2x" 150 | } 151 | ], 152 | "info" : { 153 | "version" : 1, 154 | "author" : "xcode" 155 | } 156 | } -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-568h@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-568h@2x~iphone.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-667h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-667h.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-736h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-736h.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-Landscape-736h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-Landscape-736h.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default@2x~iphone.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/platforms/ios/Ruby China/Images.xcassets/LaunchImage.launchimage/Default~iphone.png -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Ruby China-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIcons 12 | 13 | CFBundleIcons~ipad 14 | 15 | CFBundleIdentifier 16 | org.ruby-china.app 17 | CFBundleInfoDictionaryVersion 18 | 6.0 19 | CFBundleName 20 | ${PRODUCT_NAME} 21 | CFBundlePackageType 22 | APPL 23 | CFBundleShortVersionString 24 | 1.2.8 25 | CFBundleSignature 26 | ???? 27 | CFBundleVersion 28 | 10 29 | GCM_SENDER_ID 30 | aaaaaa 31 | IS_GCM_ENABLED 32 | 33 | ITSAppUsesNonExemptEncryption 34 | 35 | LSRequiresIPhoneOS 36 | 37 | NSAppTransportSecurity 38 | 39 | NSAllowsArbitraryLoads 40 | 41 | 42 | NSMainNibFile~ipad 43 | 44 | UIBackgroundModes 45 | 46 | remote-notification 47 | 48 | UIRequiresFullScreen 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China/Ruby China-Prefix.pch: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | // 20 | // Prefix header for all source files of the 'Ruby China' target in the 'Ruby China' project 21 | // 22 | 23 | #ifdef __OBJC__ 24 | #import 25 | #import 26 | #endif 27 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Ruby China 35 | 36 | Official Ruby China Mobile App for iOS and Android. 37 | 38 | 39 | Ruby China Team 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /platforms/ios/Ruby China/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | // 20 | // main.m 21 | // Ruby China 22 | // 23 | // Created by ___FULLUSERNAME___ on ___DATE___. 24 | // Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved. 25 | // 26 | 27 | #import 28 | 29 | int main(int argc, char* argv[]) 30 | { 31 | @autoreleasepool { 32 | int retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate"); 33 | return retVal; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /platforms/ios/frameworks.json: -------------------------------------------------------------------------------- 1 | { 2 | "SafariServices.framework": 1, 3 | "AddressBook.framework": 1, 4 | "libsqlite3.tbd": 1, 5 | "libz.tbd": 1 6 | } -------------------------------------------------------------------------------- /platforms/ios/ios.json: -------------------------------------------------------------------------------- 1 | { 2 | "prepare_queue": { 3 | "installed": [], 4 | "uninstalled": [] 5 | }, 6 | "config_munge": { 7 | "files": { 8 | "config.xml": { 9 | "parents": { 10 | "/*": [ 11 | { 12 | "xml": "", 13 | "count": 1 14 | }, 15 | { 16 | "xml": "", 17 | "count": 1 18 | }, 19 | { 20 | "xml": "", 21 | "count": 1 22 | }, 23 | { 24 | "xml": "", 25 | "count": 1 26 | }, 27 | { 28 | "xml": "", 29 | "count": 1 30 | }, 31 | { 32 | "xml": "", 33 | "count": 1 34 | }, 35 | { 36 | "xml": "", 37 | "count": 1 38 | } 39 | ] 40 | } 41 | }, 42 | "*-Info.plist": { 43 | "parents": { 44 | "UIBackgroundModes": [ 45 | { 46 | "xml": "remote-notification", 47 | "count": 1 48 | } 49 | ], 50 | "GCM_SENDER_ID": [ 51 | { 52 | "xml": "aaaaaa", 53 | "count": 1 54 | } 55 | ], 56 | "IS_GCM_ENABLED": [ 57 | { 58 | "xml": "", 59 | "count": 1 60 | } 61 | ] 62 | } 63 | } 64 | } 65 | }, 66 | "installed_plugins": { 67 | "cordova-plugin-app-version": { 68 | "PACKAGE_NAME": "org.ruby-china.app" 69 | }, 70 | "cordova-plugin-device": { 71 | "PACKAGE_NAME": "org.ruby-china.app" 72 | }, 73 | "cordova-plugin-safariviewcontroller": { 74 | "PACKAGE_NAME": "org.ruby-china.app" 75 | }, 76 | "cordova-plugin-statusbar": { 77 | "PACKAGE_NAME": "org.ruby-china.app" 78 | }, 79 | "cordova-plugin-whitelist": { 80 | "PACKAGE_NAME": "org.ruby-china.app" 81 | }, 82 | "phonegap-plugin-push": { 83 | "SENDER_ID": "aaaaaa", 84 | "PACKAGE_NAME": "org.ruby-china.app" 85 | } 86 | }, 87 | "dependent_plugins": {}, 88 | "modules": [ 89 | { 90 | "file": "plugins/cordova-plugin-app-version/www/AppVersionPlugin.js", 91 | "id": "cordova-plugin-app-version.AppVersionPlugin", 92 | "pluginId": "cordova-plugin-app-version", 93 | "clobbers": [ 94 | "cordova.getAppVersion" 95 | ] 96 | }, 97 | { 98 | "file": "plugins/cordova-plugin-device/www/device.js", 99 | "id": "cordova-plugin-device.device", 100 | "pluginId": "cordova-plugin-device", 101 | "clobbers": [ 102 | "device" 103 | ] 104 | }, 105 | { 106 | "file": "plugins/cordova-plugin-safariviewcontroller/www/SafariViewController.js", 107 | "id": "cordova-plugin-safariviewcontroller.SafariViewController", 108 | "pluginId": "cordova-plugin-safariviewcontroller", 109 | "clobbers": [ 110 | "SafariViewController" 111 | ] 112 | }, 113 | { 114 | "file": "plugins/cordova-plugin-statusbar/www/statusbar.js", 115 | "id": "cordova-plugin-statusbar.statusbar", 116 | "pluginId": "cordova-plugin-statusbar", 117 | "clobbers": [ 118 | "window.StatusBar" 119 | ] 120 | }, 121 | { 122 | "file": "plugins/phonegap-plugin-push/www/push.js", 123 | "id": "phonegap-plugin-push.PushNotification", 124 | "pluginId": "phonegap-plugin-push", 125 | "clobbers": [ 126 | "PushNotification" 127 | ] 128 | } 129 | ], 130 | "plugin_metadata": { 131 | "cordova-plugin-app-version": "0.1.8", 132 | "cordova-plugin-device": "1.1.2", 133 | "cordova-plugin-safariviewcontroller": "1.4.3", 134 | "cordova-plugin-statusbar": "2.1.3", 135 | "cordova-plugin-whitelist": "1.2.2", 136 | "phonegap-plugin-push": "1.7.4" 137 | } 138 | } -------------------------------------------------------------------------------- /platforms/platforms.json: -------------------------------------------------------------------------------- 1 | { 2 | "ios": "4.1.1" 3 | } -------------------------------------------------------------------------------- /resources/android/icon/drawable-hdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/icon/drawable-hdpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-ldpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/icon/drawable-ldpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-mdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/icon/drawable-mdpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-xhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/icon/drawable-xhdpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-xxhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/icon/drawable-xxhdpi-icon.png -------------------------------------------------------------------------------- /resources/android/icon/drawable-xxxhdpi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/icon/drawable-xxxhdpi-icon.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-hdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/splash/drawable-land-hdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-ldpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/splash/drawable-land-ldpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-mdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/splash/drawable-land-mdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-xhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/splash/drawable-land-xhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-xxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/splash/drawable-land-xxhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-land-xxxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/splash/drawable-land-xxxhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-hdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/splash/drawable-port-hdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-ldpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/splash/drawable-port-ldpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-mdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/splash/drawable-port-mdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-xhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/splash/drawable-port-xhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-xxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/splash/drawable-port-xxhdpi-screen.png -------------------------------------------------------------------------------- /resources/android/splash/drawable-port-xxxhdpi-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/android/splash/drawable-port-xxxhdpi-screen.png -------------------------------------------------------------------------------- /resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/icon.png -------------------------------------------------------------------------------- /resources/icon_trans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/icon_trans.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-40.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-40@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-50.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-50@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-60.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-60@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-60@3x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-72.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-72@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-76.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-76@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-small.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-small@2x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon-small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon-small@3x.png -------------------------------------------------------------------------------- /resources/ios/icon/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon.png -------------------------------------------------------------------------------- /resources/ios/icon/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/icon/icon@2x.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-568h@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/splash/Default-568h@2x~iphone.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-667h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/splash/Default-667h.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-736h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/splash/Default-736h.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Landscape-736h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/splash/Default-Landscape-736h.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Landscape@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/splash/Default-Landscape@2x~ipad.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Landscape~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/splash/Default-Landscape~ipad.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Portrait@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/splash/Default-Portrait@2x~ipad.png -------------------------------------------------------------------------------- /resources/ios/splash/Default-Portrait~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/splash/Default-Portrait~ipad.png -------------------------------------------------------------------------------- /resources/ios/splash/Default@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/splash/Default@2x~iphone.png -------------------------------------------------------------------------------- /resources/ios/splash/Default~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/ios/splash/Default~iphone.png -------------------------------------------------------------------------------- /resources/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/resources/splash.png -------------------------------------------------------------------------------- /scss/_base.scss: -------------------------------------------------------------------------------- 1 | html { 2 | // 16px = 1em; rem = root em 即根据 html 设置的百分比来 3 | // 因此设置字体基准:16px * 62.5% = 10px 4 | // 这样其他字体就可以这样定义:12px = 1.2rem,14px = 1.4rem 5 | font-size: 62.5%; 6 | } 7 | 8 | body { 9 | font-family: "Roboto", "RobotoDraft", "Helvetica Neue", Helvetica, Arial, sans-serif !important; 10 | } 11 | 12 | .bar-assertive { 13 | background-color: $assertive; 14 | box-shadow: 0 0px 1px rgba(0, 0, 0, 0.14); 15 | } 16 | 17 | .bar-header { 18 | .back-button { 19 | min-width: 35px; 20 | } 21 | } 22 | 23 | .bg-assertive, 24 | .bg-positive, 25 | .bg-balanced { 26 | color: $light; 27 | } 28 | 29 | .bg-assertive { 30 | background-color: $assertive; 31 | } 32 | 33 | .bg-positive { 34 | background-color: $positive; 35 | } 36 | 37 | .bg-stable { 38 | background-color: $stable; 39 | } 40 | 41 | .bg-balanced { 42 | background-color: $balanced; 43 | } 44 | 45 | .bg-light-gray { 46 | background-color: $light-gray; 47 | } 48 | 49 | /* 浮动按钮 */ 50 | .button-fab { 51 | line-height: 0; padding: 0; 52 | border-radius: 180px; 53 | min-width: 45px; min-height: 45px; 54 | width: 45px; height: 45px; 55 | overflow: hidden; 56 | color: #FFF; 57 | 58 | box-shadow: 0 2px 2px rgba(0, 0, 0, 0.24); 59 | 60 | i { font-size: 28px; } 61 | } 62 | 63 | .button-fab-bottom-right { 64 | position: fixed; 65 | left: auto; top: auto; 66 | right: 20px; bottom: 20px; 67 | } 68 | 69 | .gray { 70 | color: $gray; 71 | } 72 | 73 | .black { 74 | color: black; 75 | } 76 | 77 | .item-narrow { 78 | min-height: 30px !important; 79 | padding: 6px 12px; 80 | .badge { 81 | display: flex; 82 | position: absolute; 83 | top: 6px; 84 | right: 0px; 85 | } 86 | } 87 | 88 | .item-block { 89 | min-height: 40px !important; 90 | padding: 0; 91 | } 92 | 93 | .item-bottom { 94 | position: absolute; 95 | bottom: 0; 96 | } 97 | 98 | .item-noborder { 99 | border: none !important; 100 | } 101 | 102 | .item-divider-narrow { 103 | min-height: 15px !important; 104 | } 105 | 106 | textarea { 107 | width: 98%; 108 | resize: none; 109 | box-sizing: border-box; 110 | overflow-x: hidden; 111 | overflow-y: scroll; 112 | } 113 | 114 | .text-sm { 115 | font-size: 14px; 116 | } 117 | 118 | .text-deleted { 119 | color: #aaa; 120 | font-size: 12px; 121 | margin-top: 6px; 122 | text-decoration: line-through; 123 | } 124 | 125 | .item h2 { 126 | font-weight: 300; 127 | } 128 | 129 | .pull-right { 130 | float: right; 131 | } 132 | 133 | .flat, 134 | .flat.button, 135 | .flat.button.icon, 136 | .flat.hero, 137 | .flat.tabs { 138 | border: 0px; 139 | box-shadow: 0 0 0 0; 140 | } 141 | 142 | .list .item-avatar { 143 | min-height: 80px; 144 | } 145 | 146 | .list .item { 147 | border: 0.06em solid #e0e0e0; 148 | } 149 | 150 | .item.active, 151 | .item.activated, 152 | .item-complex.active .item-content, 153 | .item-complex.activated .item-content, 154 | .item .item-content.active, 155 | .item .item-content.activated { 156 | background: #FFFAF4; 157 | } 158 | 159 | .card>.item-avatar, 160 | .item-avatar, 161 | .item-avatar .item-content, 162 | .item-avatar-left, 163 | .item-avatar-left .item-content { 164 | padding-left: 70px; 165 | } 166 | 167 | .item, 168 | .item h1, 169 | .item h2, 170 | .item h3, 171 | .item h4, 172 | .item h5, 173 | .item h6, 174 | .item p, 175 | .item-content, 176 | .item-content h1, 177 | .item-content h2, 178 | .item-content h3, 179 | .item-content h4, 180 | .item-content h5, 181 | .item-content h6, 182 | .item-content p { 183 | font-family: Helvetica,Arial,"PingFang SC","Hiragino Sans GB","Source Han Sans CN",Roboto,"Heiti SC","Microsoft Yahei",sans-serif !important; 184 | white-space: normal; 185 | } 186 | 187 | .action-sheet { 188 | .button { 189 | box-shadow: none; 190 | } 191 | } 192 | 193 | // .keyboard-open { 194 | // .bar-footer { 195 | // transform: translate3d(0px, -213px, 0px) !important; 196 | // } 197 | // } 198 | 199 | #loading-bar .bar { 200 | top:0px !important; 201 | } 202 | 203 | #loading-bar-spinner { 204 | display: none; 205 | } 206 | -------------------------------------------------------------------------------- /scss/_markdown.scss: -------------------------------------------------------------------------------- 1 | /* Markdown Styles */ 2 | 3 | /* Markdown Styles */ 4 | .markdown { 5 | position:relative; 6 | line-height: 1.8em; font-size:14px; text-overflow: ellipsis; word-wrap: break-word; 7 | font-family: "PingFang SC","Hiragino Sans GB",Helvetica,Arial,"Source Han Sans CN",Roboto,"Heiti SC","Microsoft Yahei",sans-serif !important; 8 | img { max-width: 100%; } 9 | p, 10 | pre, 11 | ul, 12 | ol, 13 | blockquote { margin-bottom: 16px; } 14 | 15 | p { font-size: 14px; line-height: 1.5em; } 16 | hr { border:2px dashed $gray; border-bottom:0px; margin: 18px auto; width:50%; } 17 | blockquote { 18 | margin: 0 18px 15px 18px; 19 | padding: 0; 20 | padding-left: 32px; 21 | border: 0px; 22 | quotes: "\201C""\201D""\2018""\2019"; 23 | position: relative; 24 | line-height: 1.45; 25 | p { display:inline; color: #999; } 26 | &:before, 27 | &:after { 28 | display: block; 29 | content: "\201C"; 30 | font-size: 35px; 31 | position: absolute; 32 | font-family: serif; 33 | left: 0px; 34 | top: 0px; 35 | color: #aaa; 36 | } 37 | } 38 | pre { 39 | font-family: Menlo, Monaco, "Courier New", monospace; 40 | font-size: 12px; 41 | background-color: #F5F5F5; 42 | border: 0px; 43 | padding: 5px; 44 | color: #444; 45 | overflow: auto; 46 | border-radius: 0px; 47 | code { 48 | display: block; 49 | line-height: 150%; 50 | padding: 0!important; 51 | font-size: 12px!important; 52 | background-color: #F5F5F5 !important; 53 | border: none!important; } 54 | } 55 | p:last-child, 56 | blockquote:last-child, 57 | pre:last-child { margin-bottom:0; } 58 | pre::-webkit-scrollbar { 59 | height: 8px; 60 | width: 8px; } 61 | 62 | pre::-webkit-scrollbar-thumb:horizontal { 63 | width: 25px; 64 | background-color: #ccc; 65 | -webkit-border-radius: 4px; } 66 | 67 | pre::-webkit-scrollbar-track-piece { 68 | margin-bottom: 10px; 69 | background-color: #e5e5e5; 70 | border-bottom-left-radius: 4px 4px; 71 | border-bottom-right-radius: 4px 4px; 72 | border-top-left-radius: 4px 4px; 73 | border-top-right-radius: 4px 4px; } 74 | 75 | pre::-webkit-scrollbar-thumb:vertical { 76 | height: 25px; 77 | background-color: #ccc; 78 | -webkit-border-radius: 4px; 79 | -webkit-box-shadow: 0 1px 1px white; } 80 | 81 | code { 82 | font-size: 12px!important; 83 | background-color: #F5F5F5 !important; 84 | color: #444 !important; 85 | padding: 1px 2px !important; 86 | border: 0px; 87 | margin: 2px; 88 | border-radius: 0px; 89 | word-break: break-all; 90 | line-height: 20px; 91 | font-family:Monaco,Menlo, "Courier New", monospace; 92 | } 93 | a:link, 94 | a:visited { 95 | color:#0069D6 !important; text-decoration: none !important; 96 | } 97 | a:hover { text-decoration: underline !important; color:#00438A !important; } 98 | a.mention-floor { color:#60b566 !important; margin-right: 3px; } 99 | a.mention { 100 | color:#777 !important; font-weight: bold; 101 | margin-right: 2px; 102 | b { color:#777 !important; font-weight: normal; } 103 | } 104 | h1, 105 | h2, 106 | h3, 107 | h4, 108 | h5, 109 | h6 { 110 | font-weight:bold; text-align:left; 111 | margin-top: 10px !important; margin-bottom: 16px; 112 | } 113 | h1 { font-size: 26px !important; text-align: center; margin-bottom: 30px !important; } 114 | h2, 115 | h3, 116 | h4 { 117 | text-align: left; 118 | font-weight: bold; 119 | font-size: 16px !important; 120 | line-height: 100%; 121 | margin: 0; color: #555; 122 | margin-top: 16px; margin-bottom:16px; 123 | border-bottom:1px solid #eee; 124 | padding-bottom: 5px; 125 | } 126 | h2 { font-size: 20px !important; border-bottom-width: 2px; padding-bottom: 15px; margin-top: 20px; margin-bottom:20px; color: #111; } 127 | h3 { font-size: 18px !important; padding-bottom: 10px; margin-top: 20px; margin-bottom: 20px; color: #333; } 128 | h5, h6 { font-size: 15px; line-height: 100%; color: #777; } 129 | h6 { font-size: 14px; color: #999; } 130 | 131 | strong { color:#000; } 132 | ul, 133 | ol { 134 | list-style-position: inside; 135 | list-style-type: square; 136 | margin:0; 137 | margin-bottom: 20px; 138 | padding:0px 20px; 139 | p, 140 | blockquote, 141 | pre { margin-bottom:8px; } 142 | li { line-height:1.6em; padding:2px 0; color:#333; } 143 | ul { list-style-type: circle; margin-bottom: 0px; } 144 | } 145 | ol { 146 | list-style-type: decimal; 147 | ol { list-style-type: lower-alpha; margin-bottom: 0px; } 148 | } 149 | img { vertical-align: top; max-width: 100%; } 150 | a.zoom-image { cursor: zoom-in; } 151 | a.at_floor { color: #60B566 !important; } 152 | a.at_user { color: #0069D6 !important; } 153 | img.twemoji { width: 20px; } 154 | } 155 | 156 | .highlight .hll { background-color: #ffffcc } 157 | .highlight .c { color: #B0B2B0; font-style: italic } /* Comment */ 158 | .highlight .err { } /* Error */ 159 | .highlight .k { color: #AA22FF; font-weight: bold } /* Keyword */ 160 | .highlight .o { color: #666666 } /* Operator */ 161 | .highlight .cm { color: #B0B2B0; font-style: italic } /* Comment.Multiline */ 162 | .highlight .cp { color: #B0B2B0 } /* Comment.Preproc */ 163 | .highlight .c1 { color: #B0B2B0; font-style: italic } /* Comment.Single */ 164 | .highlight .cs { color: #B0B2B0; font-weight: bold } /* Comment.Special */ 165 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 166 | .highlight .ge { font-style: italic } /* Generic.Emph */ 167 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 168 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 169 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 170 | .highlight .go { color: #808080 } /* Generic.Output */ 171 | .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 172 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 173 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 174 | .highlight .gt { color: #0040D0 } /* Generic.Traceback */ 175 | .highlight .kc { color: #AA22FF; font-weight: bold } /* Keyword.Constant */ 176 | .highlight .kd { color: #AA22FF; font-weight: bold } /* Keyword.Declaration */ 177 | .highlight .kn { color: #AA22FF; font-weight: bold } /* Keyword.Namespace */ 178 | .highlight .kp { color: #AA22FF } /* Keyword.Pseudo */ 179 | .highlight .kr { color: #AA22FF; font-weight: bold } /* Keyword.Reserved */ 180 | .highlight .kt { color: #00BB00; font-weight: bold } /* Keyword.Type */ 181 | .highlight .m { color: #666666 } /* Literal.Number */ 182 | .highlight .s { color: #BB4444 } /* Literal.String */ 183 | .highlight .na { color: #BB4444 } /* Name.Attribute */ 184 | .highlight .nb { color: #AA22FF } /* Name.Builtin */ 185 | .highlight .nc { color: #0000FF } /* Name.Class */ 186 | .highlight .no { color: #880000 } /* Name.Constant */ 187 | .highlight .nd { color: #AA22FF } /* Name.Decorator */ 188 | .highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ 189 | .highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 190 | .highlight .nf { color: #00A000 } /* Name.Function */ 191 | .highlight .nl { color: #A0A000 } /* Name.Label */ 192 | .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 193 | .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ 194 | .highlight .nv { color: #B8860B } /* Name.Variable */ 195 | .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 196 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 197 | .highlight .mf { color: #666666 } /* Literal.Number.Float */ 198 | .highlight .mh { color: #666666 } /* Literal.Number.Hex */ 199 | .highlight .mi { color: #666666 } /* Literal.Number.Integer */ 200 | .highlight .mo { color: #666666 } /* Literal.Number.Oct */ 201 | .highlight .sb { color: #BB4444 } /* Literal.String.Backtick */ 202 | .highlight .sc { color: #BB4444 } /* Literal.String.Char */ 203 | .highlight .sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */ 204 | .highlight .s2 { color: #BB4444 } /* Literal.String.Double */ 205 | .highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 206 | .highlight .sh { color: #BB4444 } /* Literal.String.Heredoc */ 207 | .highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 208 | .highlight .sx { color: #008000 } /* Literal.String.Other */ 209 | .highlight .sr { color: #BB6688 } /* Literal.String.Regex */ 210 | .highlight .s1 { color: #BB4444 } /* Literal.String.Single */ 211 | .highlight .ss { color: #B8860B } /* Literal.String.Symbol */ 212 | .highlight .bp { color: #AA22FF } /* Name.Builtin.Pseudo */ 213 | .highlight .vc { color: #B8860B } /* Name.Variable.Class */ 214 | .highlight .vg { color: #B8860B } /* Name.Variable.Global */ 215 | .highlight .vi { color: #B8860B } /* Name.Variable.Instance */ 216 | .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ 217 | -------------------------------------------------------------------------------- /scss/_menu.scss: -------------------------------------------------------------------------------- 1 | #main-menu { 2 | .list { 3 | &.bottom { 4 | position: absolute; 5 | bottom: 0; 6 | width: 100%; 7 | } 8 | .item { 9 | min-height: 41px; 10 | font-size: 14px; 11 | .icon { 12 | font-size: 24px; 13 | } 14 | } 15 | 16 | .item-version { font-size: 12px; color: #AAA; } 17 | 18 | .item-notification { 19 | .count { display: none; } 20 | &.active { 21 | .count { 22 | margin-top: 2px; 23 | line-height: 100%; 24 | float: right; 25 | display: inline; 26 | background: #F95721; 27 | font-size: 10px; 28 | padding: 2px 8px; 29 | color: #FFF; 30 | border-radius: 180px; 31 | } 32 | } 33 | } 34 | } 35 | } 36 | 37 | .bar .button.button-icon.new { color:#F9F33B; } 38 | .bar .button .back-text { display:none; } 39 | 40 | .user-bar { 41 | background: #FFF; 42 | border-bottom: 2px solid #D2D2D2; 43 | h2 { 44 | font-size: 15px; 45 | color: #222; 46 | font-weight: 400; 47 | } 48 | .level { 49 | font-size: 10px; 50 | color: #9B9B9B; 51 | } 52 | } 53 | 54 | #new-topic-modal { 55 | .node_seletor { 56 | color: #aaa; 57 | direction: ltr; 58 | max-width: 100%; 59 | padding-left: 0; 60 | padding-top: 6px; 61 | padding-bottom: 5px; 62 | } 63 | .has_node { 64 | left: 36px; 65 | } 66 | .tabs-topic { 67 | height: 40px; 68 | .icon { 69 | line-height: 36px; 70 | height: 26px; 71 | font-size: 26px; 72 | } 73 | } 74 | } 75 | 76 | .code_selector { 77 | height: 50%; 78 | top: 20%; 79 | } 80 | -------------------------------------------------------------------------------- /scss/_notifications.scss: -------------------------------------------------------------------------------- 1 | #notifications { 2 | .list { 3 | .no-result { 4 | padding: 20px; 5 | text-align: center; 6 | font-size: 14px; 7 | color: #666; 8 | } 9 | .item { 10 | padding: 10px 16px 10px 58px; 11 | min-height: 55px; 12 | img { top: 8px; left: 10px; } 13 | h2 { 14 | padding-right: 20px; 15 | margin-top: 3px; 16 | font-size: 12px; 17 | font-weight: 350; 18 | color: #666; 19 | margin-bottom: 6px; 20 | } 21 | .notify-title { color: #888; font-weight: bold; margin-bottom: 10px; } 22 | .author { 23 | font-size: 13px; 24 | margin-top: 5px; 25 | font-weight: 400; 26 | color: #555; 27 | } 28 | .badge { 29 | background: #F94D24; 30 | display: block; 31 | position: absoulte; 32 | width: 10px; height: 10px; 33 | font-size: 12px; 34 | line-height: 100%; 35 | padding: 2px; 36 | font-weight: normal; 37 | right: 5px; 38 | } 39 | 40 | .positive { color: #333; font-size: 14px;} 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scss/_topic.scss: -------------------------------------------------------------------------------- 1 | #topic-detail { 2 | .list { 3 | padding-bottom: 80px; 4 | 5 | .gray, 6 | .dark { color: #929292; font-size: 12px; } 7 | .toolbar { 8 | height: 0px; 9 | overflow: hidden; 10 | perspective: 200px; 11 | position: relative; 12 | transition: height 0.2s ease-in-out; 13 | border-top: 0px; 14 | .tab-item { 15 | i { font-size: 24px; } 16 | } 17 | 18 | .tabs { 19 | position: absolute; 20 | opacity: 0; 21 | background: #FFE054; 22 | transition: all 0.3s ease-in-out; 23 | transform: rotateX(60deg); 24 | 25 | .active { color: #DC5B2E; } 26 | } 27 | 28 | &.open .tabs { 29 | opacity: 1; 30 | transform: rotateX(0deg); 31 | } 32 | 33 | .fold-top, .fold-bottom { 34 | height: 20px; 35 | width: 312px; 36 | left: 4px; 37 | position: absolute; 38 | transition: all 0.32s ease-in-out; 39 | } 40 | 41 | &.open .fold-top, &.open .fold-bottom { 42 | background: #FFE054; 43 | transform: rotateX(0deg); 44 | width: 100%; 45 | left: 0; 46 | } 47 | 48 | .fold-top { 49 | transform-origin: top center; 50 | transform: rotateX(-90deg); 51 | top: 0; 52 | background: #FFE054; 53 | } 54 | 55 | .fold-bottom { 56 | transform-origin: bottom center; 57 | transform: rotateX(90deg); 58 | bottom: 0; 59 | background: #FFE054; 60 | } 61 | } 62 | .toolbar.open { 63 | height: 48px; 64 | } 65 | .item-avatar { 66 | min-height: 53px; 67 | border-bottom: none; 68 | padding: 6px 10px 6px 48px; 69 | img { width: 30px; height: 30px; top: 12px; left: 10px; } 70 | h2 { 71 | font-size: 13px; line-height: 30px; 72 | .gray { font-size: 0.8em; } 73 | } 74 | } 75 | 76 | .item { 77 | border-bottom: 1px solid $light-gray; 78 | 79 | .topic-title { font-weight: 500; font-size: 16px; } 80 | 81 | .active { color: #E34A2A;} 82 | 83 | span { 84 | font-size: 12px; 85 | } 86 | 87 | &.item-info { 88 | background: #f9f9f9; color: #555; 89 | span { font-size: 14px; } 90 | i { font-size: 15px; } 91 | } 92 | 93 | h2, 94 | h3 { 95 | font-weight: 300; 96 | } 97 | h2 { 98 | line-height: 40px; 99 | } 100 | h3 { 101 | font-size: 18px; 102 | } 103 | 104 | &.reply { 105 | .row { padding: 0px; } 106 | padding-top: 0; 107 | .item-avatar { 108 | padding: 10px 0; 109 | padding-left: 36px; 110 | img:first-child { 111 | position: absolute; 112 | max-width: 30px; 113 | max-height: 30px; 114 | top: 10px; 115 | } 116 | h2 { 117 | line-height: 30px !important; 118 | font-size: 13px; color: #202020; 119 | .like { 120 | margin-right: 8px; 121 | color: #AAA; 122 | 123 | i { color: #DDD; } 124 | &.active i { color: #E34A2A; } 125 | } 126 | .floor { 127 | font-size: 12px; 128 | color: #8AAA9B; 129 | margin-right: 6px; 130 | } 131 | .time { color: #AAA; font-size:11px;} 132 | } 133 | } 134 | } 135 | } 136 | } 137 | 138 | .replies-divider { padding: 2px; min-height: 5px; } 139 | } 140 | 141 | #reply-modal { 142 | .item-reply { 143 | min-height: 250px; 144 | #topic-reply { 145 | padding: 10px; 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /scss/_topics.scss: -------------------------------------------------------------------------------- 1 | #topics { 2 | .list { 3 | .item { 4 | &:visited { 5 | h2 { 6 | color: #666; 7 | } 8 | } 9 | 10 | .item-content { 11 | min-height: 5.5rem; 12 | padding: 5px 32px 5px 64px; 13 | img { 14 | top: 8px; left: 12px; 15 | } 16 | h2 { 17 | margin-top: 5px; 18 | font-size: 1.4rem; 19 | font-weight: 400; 20 | } 21 | &:visited { 22 | h2 { 23 | color: #666; 24 | } 25 | } 26 | } 27 | .badge { 28 | color: #ababab; 29 | font-size: 1.2rem; 30 | font-weight: normal; 31 | right: 8px; 32 | } 33 | .author { 34 | font-size: 1.1rem; 35 | line-height: 1.1rem; 36 | margin-top: 5px; 37 | color: #959595; 38 | .node { 39 | margin-right: 6px; 40 | font-weight: bold; 41 | } 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /scss/_user.scss: -------------------------------------------------------------------------------- 1 | #user-profile { 2 | .list { 3 | .item { 4 | margin-bottom: 1px; 5 | } 6 | .item-avatar, 7 | .item-follow .col, 8 | .item-narrow { 9 | background-color: white; 10 | } 11 | .item-divider { 12 | padding: 0; 13 | border-top: none; 14 | background-color: #F9F9F9; 15 | line-height: inherit; 16 | height: auto; 17 | .row { 18 | .button-round { 19 | max-height: 30px; 20 | max-width: 100px; 21 | padding: 0 10px; 22 | border-radius: 15px; 23 | width: 100px; 24 | .icon, 25 | .icon:before { 26 | font-size: 20px; 27 | } 28 | } 29 | } 30 | } 31 | .item-avatar { 32 | min-height: 100px; 33 | padding: 20px; 34 | text-align: center; 35 | img:first-child { 36 | max-width: 80px; 37 | max-height: 80px; 38 | position: initial; 39 | } 40 | .level { 41 | position: absolute; 42 | top: 10px; 43 | right: 10px; 44 | padding: 3px; 45 | border-radius: 2px; 46 | font-size: 12px; 47 | line-height: 14px; 48 | font-weight: 400; 49 | } 50 | h2,.positive { font-size: 14px; font-weight: normal; } 51 | .positive { font-size: 13px; font-weight: normal; color: #5E97F6; } 52 | } 53 | .user-time { font-size: 12px; color: #CCC; } 54 | .item-follow { 55 | padding: 0; 56 | border-width: 0px; 57 | .row { 58 | padding: 1px; 59 | font-size: 12px; 60 | color: #222; 61 | .positive { color: #5E97F6; font-size: 22px; } 62 | .col { 63 | padding: 20px 20px 10px; 64 | &:first-child { 65 | margin-right: 1px; 66 | } 67 | } 68 | .positive { 69 | font-size: 30px; 70 | margin-bottom: 10px; 71 | } 72 | } 73 | } 74 | .item-info { 75 | &:active { 76 | background: #FFFAF4; 77 | } 78 | i { 79 | font-size: 18px; 80 | margin-right: 4px; 81 | vertical-align: middle; 82 | } 83 | a, 84 | span.text { 85 | color: #222; 86 | text-decoration: none; 87 | font-size: 13px; 88 | } 89 | .badge { background-color: transparent; color: #999; text-align: right; font-size: 11px; font-weight: normal; } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /scss/style.scss: -------------------------------------------------------------------------------- 1 | /* 2 | To customize the look and feel of Ionic, you can override the variables 3 | in ionic's _variables.scss file. 4 | 5 | For example, you might change some of the default colors: 6 | */ 7 | 8 | $light: #fff !default; 9 | $stable: #f8f8f8 !default; 10 | $positive: #387ef5 !default; 11 | $calm: #11c1f3 !default; 12 | $balanced: #33cd5f !default; 13 | $energized: #ffc900 !default; 14 | $assertive: #ef473a !default; 15 | $royal: #886aea !default; 16 | $dark: #444 !default; 17 | $light-gray: #f1f1f1 !default; 18 | $gray: #acacac !default; 19 | $RobotoDraftFontPath: "../lib/robotodraft/fonts" !default; 20 | $RobotoDraftFontName: "RobotoDraft"; 21 | $RobotoDraftFontVersion: "1.0.0"; 22 | @import "www/lib/robotodraft/sass/robotodraft"; 23 | // Modules 24 | @import "base"; 25 | @import "markdown"; 26 | @import "menu"; 27 | @import "topics"; 28 | @import "topic"; 29 | @import "user"; 30 | @import "notifications"; 31 | -------------------------------------------------------------------------------- /www/img/default_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/www/img/default_avatar.png -------------------------------------------------------------------------------- /www/img/ionic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-china/ruby-china-ionic/2fc20f363e5908d067a6202a054702d8fa9a1e5a/www/img/ionic.png -------------------------------------------------------------------------------- /www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /www/js/app.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('rbchina', [ 6 | 'app.core', 7 | 'app.filter', 8 | 'app.controller', 9 | 'app.service' 10 | ]); 11 | })(); 12 | -------------------------------------------------------------------------------- /www/js/controllers/controller.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.controller', []); 6 | 7 | })(); 8 | -------------------------------------------------------------------------------- /www/js/controllers/notifications.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.controller') 6 | .controller('NotificationsController', NotificationsController); 7 | 8 | //////////////////////////////////////////////////////////// 9 | 10 | /* @ngInject */ 11 | function NotificationsController($scope, $rootScope, BaseService, UserService) { 12 | var vm = this; 13 | vm.current_page = 1; // 当前页码 14 | vm.notifications = []; 15 | 16 | // Functions 17 | vm.doRefresh = doRefresh; 18 | vm.loadMore = loadMore; 19 | vm.deleteAllNotifications = deleteAllNotifications; 20 | 21 | activate(); 22 | 23 | function activate() { 24 | vm.current_page = 1; 25 | 26 | loadData().then(function(result) { 27 | vm.notifications = result; 28 | var unread_items = _.filter(result, function(item) { 29 | return item.read == false; 30 | }); 31 | var ids = _.pluck(unread_items, 'id'); 32 | UserService.markNotificationsRead(ids); 33 | 34 | $rootScope.$broadcast('unread_notifications_count', 0); 35 | 36 | // BaseService.formatTopicBody(); 37 | }); 38 | } 39 | 40 | function loadData(offset) { 41 | return UserService.getUserNotifications(offset) 42 | .then(function(result) { 43 | return result; 44 | }); 45 | } 46 | 47 | function doRefresh() { 48 | vm.current_page = 1; 49 | loadData().then(function(result) { 50 | vm.notifications = result; 51 | $scope.$broadcast('scroll.refreshComplete'); 52 | }); 53 | } 54 | 55 | function loadMore() { 56 | vm.current_page++; 57 | return loadData(vm.current_page) 58 | .then(function(result) { 59 | vm.has_more = result.items && result.items.length > 0; 60 | if (!vm.has_more) { 61 | vm.current_page--; 62 | } else { 63 | vm.notifications = _.union(vm.notifications, result.items); 64 | $scope.$broadcast('scroll.infiniteScrollComplete'); 65 | } 66 | }); 67 | } 68 | 69 | function deleteAllNotifications() { 70 | BaseService.confirm("清除通知", "", "确定要将你的所有通知清空吗?").then(function(res) { 71 | if (res) { 72 | UserService.deleteAllNotifications().then(function(res) { 73 | doRefresh(); 74 | }); 75 | } 76 | }); 77 | } 78 | 79 | $scope.$on('$ionicView.beforeEnter', function(viewInfo, state) { 80 | BaseService.statusBar(0); 81 | }); 82 | 83 | } 84 | 85 | })(); 86 | -------------------------------------------------------------------------------- /www/js/controllers/topic.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.controller') 6 | .controller('TopicController', TopicController); 7 | 8 | //////////////////////////////////////////////////////////// 9 | 10 | /* @ngInject */ 11 | function TopicController($rootScope, $scope, $stateParams, $timeout, $ionicActionSheet, 12 | $ionicPopup, $location, $ionicPosition, $ionicScrollDelegate, 13 | BaseService, AuthService, TopicService, CameraService) { 14 | 15 | var vm = this; 16 | vm.is_logined = false; 17 | vm.current_user = null; 18 | vm.user_liked_reply_ids = []; 19 | vm.meta = {}; 20 | vm.topic = { 21 | user: { 22 | avatar_url: 'img/default_avatar.png' 23 | }, 24 | likes_count: 0, 25 | body_html: '', 26 | title: '' 27 | }; 28 | vm.replies = []; 29 | vm.reply_content = ""; 30 | vm.current_page = 1; // 当前页码 31 | 32 | // Functions 33 | vm.showReplies = showReplies; 34 | vm.showTopicPopupMenu = showTopicPopupMenu; 35 | vm.showReplyModal = showReplyModal; 36 | vm.closeReplyModal = closeReplyModal; 37 | vm.moreAction = moreAction; 38 | vm.saveReply = saveReply; 39 | vm.loadMore = loadMore; 40 | vm.quoteReply = quoteReply; 41 | vm.editReply = editReply; 42 | vm.destroyReply = destroyReply; 43 | vm.likeReply = likeReply; 44 | vm.isReplyLiked = isReplyLiked; 45 | 46 | activate(); 47 | 48 | function openUrl() { 49 | console.log('open'); 50 | } 51 | 52 | function activate() { 53 | 54 | vm.is_logined = AuthService.isAuthencated(); 55 | vm.current_user = AuthService.getCurrentUser(); 56 | vm.reply_content = ""; 57 | BaseService.registModal('modals/reply.html', 'reply-modal', $scope, { 58 | focusFirstInput: true 59 | }); 60 | 61 | TopicService.getTopic($stateParams.topic_id).then(function(result) { 62 | vm.meta = result.meta; 63 | vm.topic = result.topic; 64 | // BaseService.formatTopicBody(); 65 | }); 66 | 67 | TopicService.getRepliesByTopic($stateParams.topic_id, 0).then(function(result) { 68 | vm.replies = result.replies; 69 | vm.user_liked_reply_ids = result.meta.user_liked_reply_ids || []; 70 | vm.has_more = vm.replies.length === 150; // 默认这里 100 条一页 71 | // BaseService.formatTopicBody(); 72 | }); 73 | } 74 | 75 | function showReplyModal() { 76 | vm.edit_reply_id = null; 77 | vm.reply_content = ""; 78 | vm.is_logined = AuthService.isAuthencated(); 79 | if (!vm.is_logined) { 80 | BaseService.showModal('login-modal'); 81 | } else { 82 | BaseService.showModal('reply-modal'); 83 | } 84 | } 85 | 86 | function quoteReply(reply, floor) { 87 | vm.current_edit_reply = null; 88 | vm.reply_content = "#" + floor + "楼 @" + reply.user.login + " "; 89 | BaseService.showModal('reply-modal'); 90 | } 91 | 92 | function likeReply(reply) { 93 | var liked = isReplyLiked(reply); 94 | TopicService.like('reply', reply.id, liked).then(function(result) { 95 | reply.likes_count = result.count; 96 | if (liked) { 97 | _.remove(vm.user_liked_reply_ids, function(id) { 98 | return id == reply.id 99 | }); 100 | } else { 101 | vm.user_liked_reply_ids.push(reply.id); 102 | } 103 | }); 104 | } 105 | 106 | function isReplyLiked(reply) { 107 | return vm.user_liked_reply_ids.indexOf(reply.id) != -1; 108 | } 109 | 110 | function editReply(reply) { 111 | vm.current_edit_reply = reply; 112 | TopicService.getReply(reply.id).then(function(result) { 113 | vm.reply_content = result.reply.body; 114 | BaseService.showModal('reply-modal'); 115 | }); 116 | } 117 | 118 | function destroyReply(reply) { 119 | BaseService.confirm('删除确认', '', '你确定要删除这个回帖么?').then(function(res) { 120 | TopicService.destroyReply(reply.id).then(function(result) { 121 | reply.deleted = true; 122 | }); 123 | }); 124 | } 125 | 126 | function closeReplyModal() { 127 | BaseService.hideModal('reply-modal'); 128 | } 129 | 130 | function showTopicPopupMenu() { 131 | vm.is_logined = AuthService.isAuthencated(); 132 | if (!vm.is_logined) { 133 | BaseService.showModal('login-modal'); 134 | return true; 135 | }; 136 | 137 | var likeButton = { text: ' 赞' }; 138 | var unlikeButton = { text: ' 取消赞' }; 139 | var favoriteButton = { text: ' 收藏' }; 140 | var unfavoriteButton = { text: ' 取消收藏' }; 141 | var followButton = { text: ' 关注' }; 142 | var unfollowButton = { text: ' 取消关注' }; 143 | var banButton = { text: ' 屏蔽' }; 144 | var deleteButton = { text: ' 删除' }; 145 | 146 | var buttons = []; 147 | if (vm.meta.liked) { 148 | buttons.push(unlikeButton); 149 | } else { 150 | buttons.push(likeButton); 151 | } 152 | 153 | if (vm.meta.favorited) { 154 | buttons.push(unfavoriteButton); 155 | } else { 156 | buttons.push(favoriteButton); 157 | } 158 | 159 | if (vm.meta.followed) { 160 | buttons.push(unfollowButton); 161 | } else { 162 | buttons.push(followButton); 163 | } 164 | 165 | if (vm.is_logined && vm.current_user.level == 'admin') { 166 | buttons.push(banButton); 167 | } 168 | 169 | if (vm.topic.abilities.destroy) { 170 | buttons.push(deleteButton); 171 | } 172 | 173 | var options = { 174 | buttons: buttons, 175 | cancelText: '取消', 176 | buttonClicked: function(index) { 177 | if (index == buttons.indexOf(likeButton)) { 178 | TopicService.likeTopic(vm.topic.id).then(function(result) { 179 | vm.topic.likes_count = result.count; 180 | vm.meta.liked = true; 181 | }); 182 | } 183 | 184 | if (index == buttons.indexOf(unlikeButton)) { 185 | TopicService.unlikeTopic(vm.topic.id).then(function(result) { 186 | vm.topic.likes_count = result.count; 187 | vm.meta.liked = false; 188 | }); 189 | } 190 | 191 | if (index == buttons.indexOf(favoriteButton) || index == buttons.indexOf(unfavoriteButton)) { 192 | TopicService.favorite(vm.topic.id, vm.meta.favorited).then(function(res) { 193 | vm.meta.favorited = !vm.meta.favorited; 194 | }); 195 | } 196 | 197 | if (index == buttons.indexOf(followButton) || index == buttons.indexOf(unfollowButton)) { 198 | TopicService.follow(vm.topic.id, vm.meta.followed).then(function(res) { 199 | vm.meta.followed = !vm.meta.followed; 200 | }); 201 | } 202 | 203 | if (index == buttons.indexOf(banButton)) { 204 | TopicService.ban(vm.topic.id).then(function(res) { 205 | BaseService.alert('屏蔽话题', '', '已经成功将话题移到了 NoPoint 节点。'); 206 | vm.topic.node_name = "NoPoint"; 207 | }); 208 | } 209 | 210 | if (index == buttons.indexOf(deleteButton)) { 211 | BaseService.confirm('删除确认', '', '你确定要删除这个话题么?').then(function(res) { 212 | TopicService.destroy(vm.topic.id).then(function(result) { 213 | $location.path('/app/topics/last_actived'); 214 | }); 215 | }); 216 | } 217 | 218 | return true; 219 | } 220 | }; 221 | return $ionicActionSheet.show(options); 222 | } 223 | 224 | function moreAction() { 225 | var options = { 226 | buttons: [{ 227 | text: ' 从相册添加图片' 228 | }, { 229 | text: ' 从相机添加图片' 230 | }], 231 | titleText: '更多', 232 | cancelText: '取消', 233 | buttonClicked: function(index) { 234 | document.addEventListener("deviceready", function() { 235 | var size = { 236 | width: 800, 237 | height: 600 238 | }; 239 | return CameraService.getPicture(index, size, 0) 240 | .then(function(result) { 241 | BaseService.uploadPicture(result) 242 | .then(function(img) { 243 | var img_url = '![](' + img.image_url + ')'; 244 | var prev = vm.reply_content.length === 0 ? '' : vm.reply_content + "\r\n"; 245 | vm.reply_content = prev + img_url; 246 | }); 247 | }); 248 | }, false); 249 | 250 | return true; 251 | } 252 | } 253 | return $ionicActionSheet.show(options); 254 | } 255 | 256 | 257 | // 提交回帖 258 | function saveReply() { 259 | if (vm.current_edit_reply) { 260 | TopicService.updateReply(vm.current_edit_reply.id, vm.reply_content) 261 | .then(function(result) { 262 | closeReplyModal(); 263 | var idx = vm.replies.indexOf(vm.current_edit_reply); 264 | vm.replies[idx].body_html = result.reply.body_html; 265 | vm.current_edit_reply = null; 266 | vm.reply_content = ''; 267 | }); 268 | } else { 269 | TopicService.createReply($stateParams.topic_id, vm.reply_content) 270 | .then(function(result) { 271 | closeReplyModal(); 272 | vm.replies.push(result.reply); 273 | vm.reply_content = ""; 274 | }).catch(function(err) { 275 | BaseService.alert('提交回复', '', '提交失败!'); 276 | }) 277 | } 278 | } 279 | 280 | function loadMore() { 281 | vm.current_page++; 282 | var offset = ((vm.current_page || 0) - 1) * 20; 283 | return TopicService.getRepliesByTopic($stateParams.topic_id, offset) 284 | .then(function(result) { 285 | vm.has_more = result.replies && result.replies.length > 0; 286 | if (!vm.has_more) { 287 | vm.current_page--; 288 | } else { 289 | vm.replies = _.union(vm.replies, result.replies); 290 | vm.user_liked_reply_ids = _.union(vm.user_liked_reply_ids, result.meta.user_liked_reply_ids); 291 | $scope.$broadcast('scroll.infiniteScrollComplete'); 292 | } 293 | }); 294 | } 295 | 296 | function showReplies() { 297 | var pos = $ionicPosition.position(angular.element(document.getElementById('topic-stats'))); 298 | $ionicScrollDelegate.scrollTo(0, pos.top, true); 299 | } 300 | 301 | $scope.$on('$ionicView.beforeEnter', function(viewInfo, state) { 302 | BaseService.statusBar(0); 303 | }); 304 | 305 | $scope.$on('$ionicView.leave', function(viewInfo, state) { 306 | if (state.direction === "back") { 307 | BaseService.recycleModalById('reply-modal'); 308 | } 309 | }) 310 | } 311 | 312 | })(); 313 | -------------------------------------------------------------------------------- /www/js/controllers/topics.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.controller') 6 | .controller('TopicsController', TopicsController); 7 | 8 | //////////////////////////////////////////////////////////// 9 | 10 | /* @ngInject */ 11 | function TopicsController($rootScope, $scope, $timeout, 12 | $stateParams, BaseService, AuthService, TopicService) { 13 | 14 | BaseService.statusBar(0); 15 | 16 | var vm = this; 17 | vm.topics = {}; 18 | vm.is_logined = AuthService.isAuthencated(); 19 | vm.current_page = 1; // 当前页码 20 | vm.has_new_notice = false; 21 | 22 | // Functions 23 | vm.doRefresh = doRefresh; 24 | vm.loadMore = loadMore; 25 | 26 | activate(); 27 | 28 | function activate() { 29 | vm.current_page = 1; 30 | 31 | loadData($stateParams.node_id, $stateParams.type) 32 | .then(function(result) { 33 | vm.topics = result; 34 | }); 35 | } 36 | 37 | function loadData(node_id, node_type, page) { 38 | var offset = ((page || 1) - 1) * 20; 39 | return TopicService.getTopics(node_id, node_type, offset) 40 | .then(function(result) { 41 | var topics = {}; 42 | topics.type = $stateParams.type; 43 | topics.title = $stateParams.node_name; 44 | topics.items = result.topics; 45 | topics.header_template = result.header_template; 46 | return topics; 47 | }) 48 | .catch(function(err) { 49 | return err; 50 | }); 51 | } 52 | 53 | function doRefresh() { 54 | vm.current_page = 1; 55 | loadData($stateParams.node_id, $stateParams.type) 56 | .then(function(result) { 57 | vm.topics = result; 58 | $scope.$broadcast('scroll.refreshComplete'); 59 | }); 60 | } 61 | 62 | function loadMore() { 63 | vm.current_page++; 64 | return loadData($stateParams.node_id, $stateParams.type, vm.current_page) 65 | .then(function(result) { 66 | vm.has_more = result.items && result.items.length > 0; 67 | if (!vm.has_more) { 68 | vm.current_page--; 69 | } else { 70 | vm.topics.items = _.union(vm.topics.items, result.items); 71 | $scope.$broadcast('scroll.infiniteScrollComplete'); 72 | } 73 | }); 74 | } 75 | 76 | $scope.$on('$ionicView.beforeEnter', function(viewInfo, state) { 77 | BaseService.statusBar(0); 78 | doRefresh(); 79 | }); 80 | 81 | $scope.$on('new_topic_success', function() { 82 | doRefresh(); 83 | }); 84 | } 85 | 86 | })(); 87 | -------------------------------------------------------------------------------- /www/js/controllers/user.controller.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.controller') 6 | .controller('UserController', UserController); 7 | 8 | //////////////////////////////////////////////////////////// 9 | 10 | /* @ngInject */ 11 | function UserController($stateParams, $rootScope, $scope, 12 | $timeout, BaseService, AuthService, UserService) { 13 | var vm = this; 14 | vm.user = {}; // 所查看的用户 15 | vm.current_user = AuthService.getCurrentUser(); // 本人 16 | vm.is_follow = false; 17 | vm.is_block = false; 18 | 19 | // Functions 20 | vm.isSelf = isSelf; 21 | vm.toggleFollow = toggleFollow; 22 | vm.toggleBlock = toggleBlock; 23 | vm.openUrl = openUrl; 24 | 25 | activate(); 26 | 27 | function activate() { 28 | 29 | return AuthService.getUserInfo($stateParams.login) 30 | .then(function(result) { 31 | 32 | vm.user = result.user; 33 | vm.is_follow = result.meta.followed; 34 | vm.is_block = result.meta.blocked; 35 | return vm.user; 36 | }); 37 | } 38 | 39 | function isSelf() { 40 | return !!vm.current_user && 41 | vm.current_user.login === $stateParams.login; 42 | } 43 | 44 | function toggleFollow() { 45 | if (!vm.current_user) { 46 | BaseService.showModal('login-modal'); 47 | return; 48 | } 49 | var follow = vm.is_follow ? 'unfollow' : 'follow'; 50 | return UserService.userAction($stateParams.login, follow) 51 | .then(function(result) { 52 | vm.is_follow ? vm.user.followers_count-- : vm.user.followers_count++; 53 | vm.is_follow = !vm.is_follow; 54 | }); 55 | } 56 | 57 | function toggleBlock() { 58 | if (!vm.current_user) { 59 | BaseService.showModal('login-modal'); 60 | return; 61 | } 62 | var block = vm.is_block ? 'unblock' : 'block'; 63 | return UserService.userAction($stateParams.login, block) 64 | .then(function(result) { 65 | vm.is_block = !vm.is_block; 66 | }); 67 | } 68 | 69 | function openUrl(url) { 70 | BaseService.openUrl(url); 71 | } 72 | 73 | $scope.$on('$ionicView.beforeEnter', function(viewInfo, state) { 74 | BaseService.statusBar(0); 75 | }); 76 | } 77 | 78 | })(); 79 | -------------------------------------------------------------------------------- /www/js/core/config.core.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.core') 6 | .config(oauthConfig) 7 | // .config(oauthConfigDevelopment) 8 | .config(backButtonConfig) 9 | .config(httpConfig) 10 | .config(jsScrolling) 11 | .constant('rbchina_api', { 12 | url_prefix: "https://ruby-china.org/api/v3" 13 | // url_prefix: "http://localhost:3000/api/v3" 14 | }); 15 | 16 | //////////////////////////////////////////////////////////// 17 | 18 | function httpConfig($httpProvider) { 19 | $httpProvider.interceptors.push(function($rootScope) { 20 | return { 21 | request: function(config) { 22 | $rootScope.$broadcast('loading:show'); 23 | return config; 24 | }, 25 | response: function(response) { 26 | $rootScope.$broadcast('loading:hide'); 27 | return response; 28 | }, 29 | 30 | responseError: function(response) { 31 | $rootScope.$broadcast('loading:hide'); 32 | if (response.status == 401) { 33 | $rootScope.$broadcast('relogin'); 34 | console.log('access_token is invalid, status', 401); 35 | } 36 | return response; 37 | } 38 | } 39 | }) 40 | } 41 | 42 | /* @ngInject */ 43 | function oauthConfig(OAuthProvider) { 44 | OAuthProvider.configure({ 45 | baseUrl: 'https://ruby-china.org', 46 | grantPath: '/oauth/token', 47 | revokePath: '/oauth/revoke', 48 | clientId: '1c58e228', 49 | clientSecret: '6d2c9cbef3e4baa56e1cf1d0db41d213105221aeff01281ac7009d21af810c58' 50 | }); 51 | } 52 | 53 | function oauthConfigDevelopment(OAuthProvider) { 54 | OAuthProvider.configure({ 55 | baseUrl: 'http://localhost:3000', 56 | grantPath: '/oauth/token', 57 | revokePath: '/oauth/revoke', 58 | clientId: '1fc177e0', 59 | clientSecret: '6259c0829ff85e06e9fc41460a429380da5f53ec9bf29a5d6742e9504819a1a3' 60 | }); 61 | } 62 | 63 | /* @ngInject */ 64 | function backButtonConfig($ionicConfigProvider) { 65 | $ionicConfigProvider.backButton.text('').icon('mdi mdi-arrow-left'); 66 | } 67 | 68 | /* @ngInject */ 69 | function jsScrolling($ionicConfigProvider) { 70 | if (!ionic.Platform.isIOS()) { 71 | $ionicConfigProvider.scrolling.jsScrolling(false); 72 | } 73 | } 74 | })(); 75 | -------------------------------------------------------------------------------- /www/js/core/core.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.core', [ 6 | // Ionic modules 7 | 'ionic', 'ngCordova', 'ui.router', 8 | // Vendors 9 | 'angularMoment', 'angular-oauth2', 10 | 'ngFileUpload', 'templates' 11 | ]); 12 | 13 | })(); 14 | -------------------------------------------------------------------------------- /www/js/core/route.core.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.core') 6 | .config(routeConfig); 7 | 8 | //////////////////////////////////////////////////////////// 9 | 10 | /* @ngInject */ 11 | function routeConfig($stateProvider, $urlRouterProvider) { 12 | $stateProvider 13 | .state('app', { 14 | url: '/app', 15 | abstract: true, 16 | templateUrl: 'menu.html', 17 | controller: 'MainController as vm' 18 | }) 19 | .state('app.topics', { 20 | url: '/topics/:type', 21 | views: { 22 | 'menuContent': { 23 | templateUrl: 'topics.html', 24 | controller: 'TopicsController as vm' 25 | } 26 | } 27 | }) 28 | .state('app.jobs', { 29 | url: '/jobs', 30 | params: { 31 | node_id: '25', // 社区招聘的ID是25 32 | node_name: '招聘' 33 | }, 34 | views: { 35 | 'menuContent': { 36 | templateUrl: 'topics.html', 37 | controller: 'TopicsController as vm' 38 | } 39 | } 40 | }) 41 | .state('app.rbdev', { 42 | url: '/rbdev', 43 | params: { 44 | node_id: '23', // 社区开发的ID是23 45 | node_name: '社区开发' 46 | }, 47 | views: { 48 | 'menuContent': { 49 | templateUrl: 'topics.html', 50 | controller: 'TopicsController as vm' 51 | } 52 | } 53 | }) 54 | .state('app.nopoint', { 55 | url: '/nopoint', 56 | params: { 57 | node_id: '61', // NoPoint的ID是61 58 | node_name: 'NoPoint' 59 | }, 60 | views: { 61 | 'menuContent': { 62 | templateUrl: 'topics.html', 63 | controller: 'TopicsController as vm' 64 | } 65 | } 66 | }) 67 | .state('app.topic', { 68 | url: '/topic/:topic_id', 69 | params: { 70 | replies_count: null 71 | }, 72 | views: { 73 | 'menuContent': { 74 | templateUrl: 'topic.html', 75 | controller: 'TopicController as vm' 76 | } 77 | } 78 | }) 79 | .state('app.user', { 80 | url: '/user/:login', 81 | views: { 82 | 'menuContent': { 83 | templateUrl: 'user/profile.html', 84 | controller: 'UserController as vm' 85 | } 86 | } 87 | }) 88 | .state('app.notification', { 89 | url: '/notifications', 90 | views: { 91 | 'menuContent': { 92 | templateUrl: 'notifications.html', 93 | controller: 'NotificationsController as vm' 94 | } 95 | } 96 | }); 97 | // if none of the above states are matched, use this as the fallback 98 | $urlRouterProvider.otherwise('/app/topics/last_actived'); 99 | } 100 | 101 | })(); 102 | -------------------------------------------------------------------------------- /www/js/core/run.core.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.core') 6 | .run(ionicRun) 7 | .run(oauthRun) 8 | .run(openUrl); 9 | 10 | //////////////////////////////////////////////////////////// 11 | 12 | /* @ngInject */ 13 | function ionicRun($rootScope, $ionicPlatform, $window, $state, amMoment) { 14 | $ionicPlatform.ready(function() { 15 | // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard 16 | // for form inputs) 17 | if (window.cordova && window.cordova.plugins.Keyboard) { 18 | cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); 19 | cordova.plugins.Keyboard.disableScroll(true); 20 | } 21 | if (window.StatusBar) { 22 | // org.apache.cordova.statusbar required 23 | StatusBar.styleLightContent(); 24 | } 25 | window.addEventListener('native.keyboardshow', function(event) { 26 | $rootScope.keyboardHeight = event.keyboardHeight; 27 | }); 28 | }) 29 | 30 | amMoment.changeLocale('zh-cn'); 31 | } 32 | 33 | /* @ngInject */ 34 | function oauthRun($rootScope, $window, OAuth) { 35 | $rootScope.$on('oauth:error', function(event, rejection) { 36 | // Ignore `invalid_grant` error - should be catched on `LoginController`. 37 | if ('invalid_grant' === rejection.data.error) { 38 | return; 39 | } 40 | 41 | // Refresh token when a `invalid_token` error occurs. 42 | if ('invalid_token' === rejection.data.error) { 43 | return OAuth.getRefreshToken(); 44 | } 45 | 46 | // Redirect to `/login` with the `error_reason`. 47 | return $window.location.href = '/login?error_reason=' + rejection.data.error; 48 | }); 49 | } 50 | 51 | /* @ngInject */ 52 | function openUrl($window, BaseService) { 53 | $window.openUrl = BaseService.openUrl; 54 | } 55 | 56 | })(); 57 | -------------------------------------------------------------------------------- /www/js/filters/exlink.filter.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.filter') 6 | .filter('externalLinks', externalLinks); 7 | 8 | /* @ngInject */ 9 | function externalLinks($sce) { 10 | return function(text) { 11 | // 说明:由于删除 jQuery 的缘故,不再使用 BaseService.formatTopicBody 方法调整链接 12 | var exlinks = /href="((http|https):\/\/[\S]+)"/gi, 13 | atuser_links = /href="(\/[\S]+)"/gi, 14 | atfloor_links = /href="(#reply[0-9]+)"/gi, 15 | output = ""; 16 | 17 | if (text.match(exlinks)) { 18 | output = $sce.trustAsHtml( 19 | text.replace(exlinks, "onClick=\"openUrl('$1')\"") 20 | ); 21 | } else if (text.match(atuser_links)) { 22 | output = $sce.trustAsHtml( 23 | text.replace(atuser_links, "href=\"#/app/user$1\"") 24 | ); 25 | } else if (text.match(atfloor_links)) { 26 | output = $sce.trustAsHtml( 27 | text.replace(atfloor_links, "") 28 | ); 29 | } else { 30 | return text; 31 | } 32 | // console.debug(output.toString()); 33 | return output; 34 | } 35 | } 36 | })(); 37 | -------------------------------------------------------------------------------- /www/js/filters/filter.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.filter', []) 6 | 7 | })(); 8 | -------------------------------------------------------------------------------- /www/js/services/auth.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.service') 6 | .factory('AuthService', AuthService); 7 | 8 | //////////////////////////////////////////////////////////// 9 | 10 | /* @ngInject */ 11 | function AuthService($q, $http, $window, OAuth, rbchina_api) { 12 | var LOCAL_TOKEN_KEY; 13 | var authToken; 14 | 15 | var service = { 16 | login: login, 17 | logout: logout, 18 | getUserInfo: getUserInfo, 19 | getAccessToken: getAccessToken, 20 | refreshAccessToken: refreshAccessToken, 21 | isAuthencated: isAuthencated, 22 | getCurrentUser: getCurrentUser, 23 | submitDeviceToken: submitDeviceToken 24 | }; 25 | 26 | // 载入用户登录信息 27 | loadUserCredentials(); 28 | 29 | return service; 30 | 31 | // 加载用户验证信息 32 | function loadUserCredentials() { 33 | var token = getAccessToken(); 34 | if (token) { 35 | useCredentials(token); 36 | } 37 | } 38 | 39 | // 存储用户验证信息 40 | function storeUserCredentials(token) { 41 | useCredentials(token); 42 | } 43 | 44 | // 激活用户验证 45 | function useCredentials(token) { 46 | authToken = token; 47 | $window.localStorage['access_token'] = token; 48 | // Set the token as header for your requests! 49 | $http.defaults.headers.common['Authorization'] = "Bearer " + token; 50 | } 51 | 52 | // 销毁用户验证 53 | function destroyUserCredentials() { 54 | authToken = undefined; 55 | $http.defaults.headers.common['Authorization'] = undefined; 56 | OAuth.revokeToken(); 57 | $window.localStorage['access_token'] = null; 58 | $window.localStorage['current_user'] = null; 59 | $window.localStorage['auth_info'] = null; 60 | setCurrentUser({}); 61 | } 62 | 63 | function getUserInfo(login) { 64 | var q = $q.defer(); 65 | var url = rbchina_api.url_prefix + '/users/' + login + '.json'; 66 | $http.get(url, { 67 | params: { 68 | access_token: authToken 69 | } 70 | }) 71 | .success(function(result) { 72 | q.resolve(result); 73 | }).error(function(err) { 74 | q.reject(err); 75 | }); 76 | return q.promise; 77 | } 78 | 79 | function setCurrentUser(user) { 80 | $window.localStorage['current_user'] = JSON.stringify(user); 81 | } 82 | 83 | function getCurrentUser() { 84 | var info = $window.localStorage['current_user']; 85 | if (!info) { 86 | return null 87 | } 88 | return JSON.parse(info); 89 | } 90 | 91 | function submitDeviceToken(token) { 92 | var q = $q.defer(); 93 | 94 | // 如果有传 Token,记录到 localStorage 95 | if (token != undefined) { 96 | $window.localStorage['device_token'] = token; 97 | } 98 | 99 | if (!isAuthencated()) { 100 | return q.promise; 101 | } 102 | 103 | var deviceToken = $window.localStorage['device_token']; 104 | if (deviceToken === undefined) { 105 | return q.promise; 106 | } 107 | 108 | var params = { 109 | platform: 'ios', 110 | token: deviceToken 111 | }; 112 | var url = rbchina_api.url_prefix + '/devices.json'; 113 | $http.post(url, params).success(function(result) { 114 | q.resolve(result); 115 | }).error(function(err) { 116 | q.reject(err); 117 | }); 118 | return q.promise; 119 | } 120 | 121 | function login(user) { 122 | var q = $q.defer(); 123 | if (!user.username) { 124 | q.reject("用户名或 Email 没有填写"); 125 | return q.promise; 126 | } 127 | 128 | if (!user.password) { 129 | q.reject("还没未填写密码"); 130 | return q.promise; 131 | } 132 | 133 | 134 | OAuth.getAccessToken(user) 135 | .then(function(result) { 136 | if (result.status == 200) { 137 | $window.localStorage['auth_info'] = JSON.stringify(user); 138 | storeUserCredentials(result.data.access_token); 139 | 140 | // 获取用户信息并存储 141 | getUserInfo('me') 142 | .then(function(response) { 143 | // 输出用户信息 144 | setCurrentUser(response.user); 145 | 146 | submitDeviceToken().then(function() { }); 147 | q.resolve(response.user); 148 | }).catch(function(error) { 149 | q.reject(error); 150 | }); 151 | } else if (result.status == 401) { 152 | q.reject("对不起,用户名或密码错误!"); 153 | } else { 154 | q.reject("未知异常,登陆失败,请稍后再重试。") 155 | } 156 | }).catch(function(err) { 157 | q.reject("对不起,用户名或密码错误!"); 158 | }); 159 | return q.promise; 160 | } 161 | 162 | function logout() { 163 | destroyUserCredentials(); 164 | } 165 | 166 | function isAuthencated() { 167 | return !!authToken && getCurrentUser().login; 168 | } 169 | 170 | function getAccessToken() { 171 | return authToken || $window.localStorage['access_token'] || null; 172 | } 173 | 174 | function refreshAccessToken() { 175 | var q = $q.defer(); 176 | var info = $window.localStorage['auth_info'] || '{}'; 177 | var user = JSON.parse(info) || {}; 178 | if (!user.username || !user.password) { 179 | console.warn('There is not user login info stored'); 180 | q.reject("No auth info") 181 | return q.promise; 182 | } 183 | 184 | return login(user); 185 | } 186 | } 187 | 188 | })(); 189 | -------------------------------------------------------------------------------- /www/js/services/base.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.service') 6 | .factory('BaseService', BaseService); 7 | 8 | //////////////////////////////////////////////////////////// 9 | 10 | /* @ngInject */ 11 | function BaseService($q, $http, $ionicLoading, $ionicPopup, 12 | $ionicModal, $ionicActionSheet, $timeout, $cordovaInAppBrowser, AuthService, rbchina_api) { 13 | 14 | var modals = []; 15 | var statusBarStyle = 0; 16 | var service = { 17 | // 弹出框 18 | alert: alert, 19 | confirm: confirm, 20 | // 加载动画 21 | showLoading: showLoading, 22 | hideLoading: hideLoading, 23 | // 模态框 24 | registModal: registModal, 25 | showModal: showModal, 26 | hideModal: hideModal, 27 | recycleModals: recycleModals, 28 | recycleModalById: recycleModalById, 29 | reserveModalById: reserveModalById, 30 | // ActionSheet 31 | showActionSheet: showActionSheet, 32 | // 上传图片 33 | uploadPicture: uploadPicture, 34 | openUrl: openUrl, 35 | dismissSafari: dismissSafari, 36 | statusBar: statusBar, 37 | formatTopicBody: formatTopicBody 38 | }; 39 | 40 | return service; 41 | 42 | ////////////////////////////////////////////////////////////////////// 43 | // 说明:由于删除 jQuery 的缘故,不再使用 BaseService.formatTopicBody 方法调整链接 44 | function formatTopicBody() { 45 | $timeout(function() { 46 | // 处理外部链接 47 | var exlinks = $('.ex-link'); 48 | 49 | // 先去掉 href 属性,防止触发内部浏览器 50 | _.forEach(exlinks, function(link) { 51 | var orig = $(link).attr("href"); 52 | $(link).removeAttr("href"); 53 | $(link).data('url', orig); 54 | // $(link).attr("ng-click", "vm.openExternLinks('" + orig + "')"); 55 | }); 56 | 57 | exlinks.click(function() { 58 | var url = $(this).data('url'); 59 | openUrl(url); 60 | return false; 61 | }); 62 | 63 | // 处理@链接 64 | var atuser_links = $('.at_user'); 65 | _.forEach(atuser_links, function(link) { 66 | var orig = $(link).attr("href") || ''; 67 | if (orig.indexOf('#/app/user/') == -1) { 68 | $(link).attr("href", "#/app/user/" + orig.slice(1)); 69 | } 70 | }); 71 | 72 | var atfloor_links = $('.at_floor'); 73 | atfloor_links.on('click', function() { 74 | return false; 75 | }); 76 | }); 77 | } 78 | 79 | // 弹出警告框 80 | function alert(title, subTitle, message) { 81 | return $ionicPopup.alert({ 82 | title: title, 83 | subTitle: subTitle, 84 | template: '

' + message + '

', 85 | okText: '知道了' 86 | }); 87 | } 88 | 89 | // 弹出确认框 90 | function confirm(title, subTitle, message) { 91 | return $ionicPopup.confirm({ 92 | title: title, 93 | subTitle: subTitle, 94 | template: '

' + message + '

', 95 | okText: '确认', 96 | cancelText: '取消' 97 | }) 98 | .then(function(res) { 99 | return res; 100 | }); 101 | } 102 | 103 | // 弹出加载界面 104 | // 可传入Spinner类型和消息 105 | function showLoading(style, message) { 106 | return $ionicLoading.show({ 107 | template: '

' + 109 | message + '

', 110 | duration: 6000 // 为避免卡死,6秒后如无反应则隐藏 111 | }); 112 | } 113 | 114 | // 结束加载动画 115 | function hideLoading() { 116 | $ionicLoading.hide(); 117 | } 118 | 119 | // 注册模态框 120 | function registModal(template_url, modal_id, scope, opts) { 121 | var defaults = { 122 | scope: scope, 123 | animation: 'slide-in-up' 124 | }; 125 | var options = _.merge(defaults, opts); 126 | return $ionicModal.fromTemplateUrl(template_url, options) 127 | .then(function(modal) { 128 | if (_.indexOf(_.pluck(modals, "id"), modal_id) === -1) { 129 | modals.push({ 130 | id: modal_id, 131 | modal: modal 132 | }); 133 | return modals; 134 | } 135 | }); 136 | } 137 | 138 | // 弹出模态框 139 | function showModal(modal_id) { 140 | changeStatusBar(1); 141 | var modal = _.find(modals, "id", modal_id).modal; 142 | return modal.show(); 143 | } 144 | 145 | // 隐藏模态框 146 | function hideModal(modal_id) { 147 | statusBar(statusBarStyle); 148 | var modal = _.find(modals, "id", modal_id).modal; 149 | return modal.hide(); 150 | } 151 | 152 | // 回收所有模态框 153 | function recycleModals() { 154 | _.forEach(modals, function(modal) { 155 | modal.modal.remove(); 156 | }); 157 | modals = []; 158 | } 159 | 160 | // 回收某个模态框 161 | function recycleModalById(modal_id) { 162 | var modal = _.find(modals, "id", modal_id).modal; 163 | modal.remove(); 164 | modals = _.reject(modals, "id", modal_id); 165 | } 166 | 167 | // 保留某个模态框 168 | function reserveModalById(modal_id) { 169 | var modal = _.find(modals, "id", modal_id).modal; 170 | _.forEach(modals, function(m) { 171 | if (modal.id !== m.modal.id) { 172 | m.modal.remove(); 173 | } 174 | }); 175 | modals = _.select(modals, "id", modal_id); 176 | } 177 | 178 | // 弹出 ActionSheet 179 | function showActionSheet(buttons, titleText, cancelText, buttonsCb, destructiveText, destructiveCb) { 180 | var options = { 181 | buttons: buttons, 182 | titleText: titleText, 183 | cancelText: cancelText, 184 | buttonClicked: buttonsCb, 185 | destructiveText: destructiveText, 186 | destructiveButtonClicked: destructiveCb 187 | }; 188 | return $ionicActionSheet.show(options); 189 | } 190 | 191 | // 上传图片 192 | function uploadPicture(file) { 193 | var q = $q.defer(); 194 | var url = rbchina_api.url_prefix + '/photos.json'; 195 | showLoading('lines', '上传中...'); 196 | var data = new FormData(); 197 | var ext = file.split(',')[0].split(':')[1].split(';')[0].split('/')[1]; 198 | data.append("file", dataURItoBlob(file), "photo." + ext); // 调了半天原来是这里Blob要加个name 199 | $http.post(url, data, { 200 | params: { 201 | access_token: AuthService.getAccessToken() 202 | }, 203 | transformRequest: angular.identity, 204 | headers: { 205 | 'Content-Type': undefined 206 | } 207 | }) 208 | .success(function(result) { 209 | hideLoading(); 210 | q.resolve(result); 211 | }) 212 | .error(function(err) { 213 | hideLoading(); 214 | q.reject(err); 215 | }); 216 | return q.promise; 217 | } 218 | 219 | // https://github.com/EddyVerbruggen/cordova-plugin-safariviewcontroller 220 | function openUrl(url) { 221 | // console.debug(url); 222 | url = encodeURI(url); 223 | 224 | SafariViewController.isAvailable(function(available) { 225 | if (available) { 226 | SafariViewController.show({ 227 | url: url, 228 | animated: false, // default true, note that 'hide' will reuse this preference (the 'Done' button will always animate though) 229 | enterReaderModeIfAvailable: false // default false 230 | }, 231 | // this success handler will be invoked for the lifecycle events 'opened', 'loaded' and 'closed' 232 | function(result) {}, 233 | function(msg) {}) 234 | } else { 235 | // potentially powered by InAppBrowser because that (currently) clobbers window.open 236 | var options = { 237 | location: 'yes', 238 | clearcache: 'yes', 239 | toolbar: 'yes' 240 | }; 241 | $cordovaInAppBrowser.open(url, '_blank', options) 242 | .then(function(event) { 243 | // success 244 | }) 245 | .catch(function(event) { 246 | // error 247 | }); 248 | } 249 | }) 250 | } 251 | 252 | function dismissSafari() { 253 | SafariViewController.hide(); 254 | } 255 | 256 | function statusBar(style) { 257 | statusBarStyle = style; 258 | changeStatusBar(style); 259 | } 260 | 261 | function changeStatusBar(style) { 262 | if (!window.StatusBar) { 263 | return; 264 | } 265 | 266 | if (style == 0) { 267 | StatusBar.styleLightContent(); 268 | } else { 269 | StatusBar.styleDefault(); 270 | } 271 | } 272 | } 273 | 274 | // base64字符串转图片格式 275 | function dataURItoBlob(dataURI) { 276 | // convert base64/URLEncoded data component to raw binary data held in a string 277 | var byteString; 278 | if (dataURI.split(',')[0].indexOf('base64') >= 0) 279 | byteString = atob(dataURI.split(',')[1]); 280 | else 281 | byteString = unescape(dataURI.split(',')[1]); 282 | 283 | // separate out the mime component 284 | var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; 285 | 286 | // write the bytes of the string to a typed array 287 | var ia = new Uint8Array(byteString.length); 288 | for (var i = 0; i < byteString.length; i++) { 289 | ia[i] = byteString.charCodeAt(i); 290 | } 291 | return new Blob([ia], { 292 | name: 'photo', 293 | type: mimeString 294 | }); 295 | } 296 | 297 | })(); 298 | -------------------------------------------------------------------------------- /www/js/services/camera.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.service') 6 | .factory('CameraService', CameraService); 7 | 8 | ////////////////////////////////////////////////////////////////////// 9 | 10 | /* @ngInject */ 11 | function CameraService($q) { 12 | var service = { 13 | getPicture: getPicture 14 | }; 15 | 16 | return service; 17 | 18 | ////////////////////////////////////////////////////////////////////// 19 | 20 | // 获取照片 21 | function getPicture(source, size, type) { 22 | var q = $q.defer(); 23 | var options = { 24 | quality: 75, 25 | destinationType: type, 26 | sourceType: source, 27 | allowEdit: true, 28 | encodingType: Camera.EncodingType.JPEG, 29 | targetWidth: size.width, 30 | targetHeight: size.height, 31 | popoverOptions: CameraPopoverOptions, /* jshint ignore:line */ 32 | saveToPhotoAlbum: false, 33 | correctOrientation: false 34 | }; 35 | 36 | navigator.camera.getPicture(function(imageData) { 37 | q.resolve("data:image/jpeg;base64," + imageData); 38 | }, function(err) { 39 | q.reject("'----- Failed because: ' + message"); 40 | }, options); 41 | 42 | return q.promise; 43 | } 44 | } 45 | })(); 46 | -------------------------------------------------------------------------------- /www/js/services/service.module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.service', []); 6 | 7 | })(); 8 | -------------------------------------------------------------------------------- /www/js/services/topic.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.service') 6 | .factory('TopicService', TopicService); 7 | 8 | //////////////////////////////////////////////////////////// 9 | 10 | /* @ngInject */ 11 | function TopicService($q, $http, AuthService, rbchina_api) { 12 | // 根据不同节点在首页显示不同的Header 13 | var topics_headers = [{ 14 | node_id: undefined, 15 | header_template: 'templates/topics/_filters.html' 16 | }]; 17 | var service = { 18 | getTopics: getTopics, 19 | getTopic: getTopic, 20 | getTopicWithReplies: getTopicWithReplies, 21 | getRepliesByTopic: getRepliesByTopic, 22 | createReply: createReply, 23 | getReply: getReply, 24 | updateReply: updateReply, 25 | destroyReply: destroyReply, 26 | getAllNodes: getAllNodes, 27 | createTopic: createTopic, 28 | likeTopic: likeTopic, 29 | unlikeTopic: unlikeTopic, 30 | like: like, 31 | favorite: favorite, 32 | follow: follow, 33 | ban: ban, 34 | destroy: destroy 35 | }; 36 | 37 | return service; 38 | 39 | function getTopics(node_id, type, offset) { 40 | var q = $q.defer(); 41 | var url = rbchina_api.url_prefix + '/topics.json'; 42 | $http.get(url, { 43 | params: { 44 | node_id: node_id, 45 | type: type, 46 | offset: offset, 47 | limit: 20 48 | } 49 | }) 50 | .success(function(result) { 51 | result.header_template = _.result(_.findWhere(topics_headers, { 52 | node_id: node_id 53 | }), 'header_template'); 54 | q.resolve(result); 55 | }).error(function(err) { 56 | q.reject(err); 57 | }); 58 | return q.promise; 59 | } 60 | 61 | function getTopic(topic_id) { 62 | var q = $q.defer(); 63 | var url = rbchina_api.url_prefix + '/topics/' + topic_id + '.json'; 64 | $http.get(url).success(function(result) { 65 | q.resolve(result); 66 | }).error(function(err) { 67 | q.reject(err); 68 | }); 69 | return q.promise; 70 | } 71 | 72 | function like(able_type, able_id, liked) { 73 | var q = $q.defer(); 74 | var url = rbchina_api.url_prefix + '/likes.json?obj_type=' + able_type + '&obj_id=' + able_id; 75 | var method = liked == true ? 'DELETE' : 'POST'; 76 | 77 | $http({ 78 | method: method, 79 | url: url 80 | }).success(function(result) { 81 | q.resolve(result); 82 | }).error(function(err) { 83 | q.reject(err); 84 | }); 85 | return q.promise; 86 | } 87 | 88 | function likeTopic(topic_id) { 89 | var q = $q.defer(); 90 | var url = rbchina_api.url_prefix + '/likes.json'; 91 | var params = { 92 | obj_type: 'topic', 93 | obj_id: topic_id, 94 | access_token: AuthService.getAccessToken() 95 | }; 96 | 97 | $http.post(url, params).success(function(result) { 98 | q.resolve(result); 99 | }).error(function(err) { 100 | q.reject(err); 101 | }); 102 | return q.promise; 103 | } 104 | 105 | function unlikeTopic(topic_id) { 106 | var q = $q.defer(); 107 | var url = rbchina_api.url_prefix + '/likes.json?obj_type=topic&obj_id=' + topic_id; 108 | 109 | $http.delete(url).success(function(result) { 110 | q.resolve(result); 111 | }).error(function(err) { 112 | q.reject(err); 113 | }); 114 | return q.promise; 115 | } 116 | 117 | function favorite(topic_id, favorited) { 118 | var q = $q.defer(); 119 | var method = favorited == true ? 'unfavorite' : 'favorite'; 120 | var url = rbchina_api.url_prefix + '/topics/' + topic_id + '/'+ method +'.json'; 121 | $http.post(url).success(function(result) { 122 | q.resolve(result); 123 | }).error(function(err) { 124 | q.reject(err); 125 | }); 126 | return q.promise; 127 | } 128 | 129 | function follow(topic_id, followd) { 130 | var q = $q.defer(); 131 | var method = followd == true ? 'unfollow' : 'follow'; 132 | var url = rbchina_api.url_prefix + '/topics/' + topic_id + '/' + method + '.json'; 133 | $http.post(url).success(function(result) { 134 | q.resolve(result); 135 | }).error(function(err) { 136 | q.reject(err); 137 | }); 138 | return q.promise; 139 | } 140 | 141 | function ban(topic_id) { 142 | var q = $q.defer(); 143 | var url = rbchina_api.url_prefix + '/topics/' + topic_id + '/ban.json'; 144 | $http.post(url).success(function(result) { 145 | q.resolve(result); 146 | }).error(function(err) { 147 | q.reject(err); 148 | }); 149 | return q.promise; 150 | } 151 | 152 | function getTopicWithReplies(topic_id) { 153 | var q = $q.defer(); 154 | getTopic(topic_id) 155 | .then(function(result) { 156 | var topic = result; 157 | var url = rbchina_api.url_prefix + '/topics/' + topic_id + '/replies.json'; 158 | $http.get(url) 159 | .success(function(response) { 160 | topic.replies = response.replies; 161 | topic.user_liked_reply_ids = response.meta.user_liked_reply_ids; 162 | q.resolve(topic); 163 | }).error(function(e) { 164 | q.reject(e); 165 | }); 166 | }); 167 | return q.promise; 168 | } 169 | 170 | function getRepliesByTopic(topic_id, offset) { 171 | var q = $q.defer(); 172 | var url = rbchina_api.url_prefix + '/topics/' + topic_id + '/replies.json'; 173 | $http.get(url, { 174 | params: { 175 | offset: offset, 176 | limit: 150 177 | } 178 | }) 179 | .success(function(result) { 180 | q.resolve(result); 181 | }).error(function(e) { 182 | q.reject(e); 183 | }); 184 | return q.promise; 185 | } 186 | 187 | function getReply(reply_id) { 188 | var q = $q.defer(); 189 | var url = rbchina_api.url_prefix + '/replies/' + reply_id + '.json'; 190 | 191 | $http.get(url) 192 | .success(function(result) { 193 | q.resolve(result); 194 | }).error(function(err) { 195 | q.reject(err); 196 | }); 197 | return q.promise; 198 | } 199 | 200 | // 提交回复 201 | function createReply(topic_id, body) { 202 | var q = $q.defer(); 203 | var url = rbchina_api.url_prefix + '/topics/' + topic_id + '/replies.json'; 204 | var data = { 205 | body: body, 206 | access_token: AuthService.getAccessToken() 207 | }; 208 | $http.post(url, data) 209 | .success(function(result) { 210 | q.resolve(result); 211 | }).error(function(err) { 212 | q.reject(err); 213 | }); 214 | return q.promise; 215 | } 216 | 217 | function updateReply(reply_id, body) { 218 | var q = $q.defer(); 219 | var url = rbchina_api.url_prefix + '/replies/' + reply_id + '.json'; 220 | 221 | $http.post(url, { body: body }) 222 | .success(function(result) { 223 | q.resolve(result); 224 | }).error(function(err) { 225 | q.reject(err); 226 | }); 227 | return q.promise; 228 | } 229 | 230 | function destroyReply(reply_id) { 231 | var q = $q.defer(); 232 | var url = rbchina_api.url_prefix + '/replies/' + reply_id + '.json'; 233 | 234 | $http.delete(url) 235 | .success(function(result) { 236 | q.resolve(result); 237 | }).error(function(err) { 238 | q.reject(err); 239 | }); 240 | return q.promise; 241 | } 242 | 243 | // 获取所有节点名称 244 | function getAllNodes() { 245 | var q = $q.defer(); 246 | var url = rbchina_api.url_prefix + '/nodes.json'; 247 | $http.get(url) 248 | .success(function(result) { 249 | q.resolve(result); 250 | }).error(function(err) { 251 | q.reject(err); 252 | }); 253 | return q.promise; 254 | } 255 | 256 | // 创建话题 257 | function createTopic(title, body, node_id) { 258 | var q = $q.defer(); 259 | var url = rbchina_api.url_prefix + '/topics.json'; 260 | var data = { 261 | title: title, 262 | body: body, 263 | node_id: node_id, 264 | access_token: AuthService.getAccessToken() 265 | }; 266 | $http.post(url, data) 267 | .success(function(result) { 268 | q.resolve(result); 269 | }).error(function(err) { 270 | q.reject(err); 271 | }); 272 | return q.promise; 273 | } 274 | 275 | function destroy(topic_id) { 276 | var q = $q.defer(); 277 | var url = rbchina_api.url_prefix + '/topics/' + topic_id + '.json'; 278 | $http.delete(url).success(function(result) { 279 | q.resolve(result); 280 | }).error(function(err) { 281 | q.reject(err); 282 | }); 283 | return q.promise; 284 | } 285 | 286 | } 287 | 288 | })(); 289 | -------------------------------------------------------------------------------- /www/js/services/user.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app.service') 6 | .factory('UserService', UserService); 7 | 8 | //////////////////////////////////////////////////////////// 9 | 10 | /* @ngInject */ 11 | function UserService($q, $http, AuthService, rbchina_api) { 12 | var service = { 13 | getUserTopics: getUserTopics, 14 | getUnreadNotificationsCount: getUnreadNotificationsCount, 15 | getUserNotifications: getUserNotifications, 16 | markNotificationsRead: markNotificationsRead, 17 | deleteAllNotifications: deleteAllNotifications, 18 | userAction: userAction 19 | }; 20 | 21 | return service; 22 | 23 | 24 | // 获取用户创建列表 25 | function getUserTopics(login) { 26 | var q = $q.defer(); 27 | var url = rbchina_api.url_prefix + '/users/' + login + '/topics.json'; 28 | $http.get(url) 29 | .success(function(result) { 30 | q.resolve(result); 31 | }).error(function(err) { 32 | q.reject(err); 33 | }); 34 | return q.promise; 35 | } 36 | 37 | function getUnreadNotificationsCount() { 38 | var q = $q.defer(); 39 | var url = rbchina_api.url_prefix + '/notifications/unread_count.json'; 40 | $http.get(url) 41 | .success(function(result) { 42 | q.resolve(result); 43 | }).error(function(err) { 44 | q.reject(err); 45 | }); 46 | return q.promise; 47 | } 48 | 49 | // 获取用户通知列表 50 | function getUserNotifications(offset) { 51 | var q = $q.defer(); 52 | var url = rbchina_api.url_prefix + '/notifications.json'; 53 | $http.get(url, { 54 | params: { 55 | offset: offset, 56 | access_token: AuthService.getAccessToken() 57 | } 58 | }) 59 | .success(function(result) { 60 | q.resolve(result.notifications); 61 | }).error(function(err) { 62 | q.reject(err); 63 | }); 64 | return q.promise; 65 | } 66 | 67 | function markNotificationsRead(ids) { 68 | var q = $q.defer(); 69 | var url = rbchina_api.url_prefix + '/notifications/read.json'; 70 | $http.post(url, { 71 | ids: ids 72 | }) 73 | .success(function(result) { 74 | q.resolve(result.notifications); 75 | }).error(function(err) { 76 | q.reject(err); 77 | }); 78 | return q.promise; 79 | } 80 | 81 | function deleteAllNotifications(ids) { 82 | var q = $q.defer(); 83 | var url = rbchina_api.url_prefix + '/notifications/all.json'; 84 | $http.delete(url).success(function(result) { 85 | q.resolve(result); 86 | }).error(function(err) { 87 | q.reject(err); 88 | }); 89 | return q.promise; 90 | } 91 | 92 | 93 | // 关注或屏蔽用户 94 | // action: follow-关注;block-屏蔽 95 | function userAction(login, action) { 96 | var q = $q.defer(); 97 | var url = rbchina_api.url_prefix + '/users/' + login + '/' + action + '.json'; 98 | var data = { 99 | login: login, 100 | access_token: AuthService.getAccessToken() 101 | } 102 | $http.post(url, data) 103 | .success(function(result) { 104 | q.resolve(result.notifications); 105 | }).error(function(err) { 106 | q.reject(err); 107 | }); 108 | return q.promise; 109 | } 110 | } 111 | 112 | })(); 113 | -------------------------------------------------------------------------------- /www/templates/menu.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 39 | 50 |
51 | 版本: 0.0.0 52 |
53 |
54 |
55 |
56 | -------------------------------------------------------------------------------- /www/templates/modals/code_selector.html: -------------------------------------------------------------------------------- 1 |
2 | {{ code.name }} 3 |
4 | -------------------------------------------------------------------------------- /www/templates/modals/login.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

账号登录

4 | 5 |
6 | 7 |
8 |
9 |
10 |
11 | 12 |
13 |
14 |
15 |
16 | 19 | 22 | 25 |
26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /www/templates/modals/new_topic.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |

5 | 6 |
7 | 8 |
9 | 13 | 20 | 23 |
24 |
25 |
26 | 27 | 44 | 45 |
46 | -------------------------------------------------------------------------------- /www/templates/modals/reply.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |

回复

5 | 6 |
7 | 8 |
9 |
10 | 11 |
12 |
13 |
14 |
15 | 19 |
20 |
21 |
22 |
23 |
24 |
25 | -------------------------------------------------------------------------------- /www/templates/notifications.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | 暂无任何通知 12 |
13 |
14 | 15 |
16 |
17 | 18 | 19 |
20 |
21 | -------------------------------------------------------------------------------- /www/templates/notifications/follow.html: -------------------------------------------------------------------------------- 1 | 2 | nf.actor.login 3 |

4 | {{ nf.actor.login }} 于 5 | 开始关注你了。 6 | 7 |

8 |
9 | -------------------------------------------------------------------------------- /www/templates/notifications/mention.html: -------------------------------------------------------------------------------- 1 | 2 | nf.actor.login 3 |

4 | {{ nf.actor.login }} 在 5 | 在帖子中提及你 6 |

7 |
{{ nf.topic.title }}
8 |
9 | 10 |
11 | -------------------------------------------------------------------------------- /www/templates/notifications/nodechanged.html: -------------------------------------------------------------------------------- 1 | 2 |

3 | 你发布的话题 {{nf.topic.title}} 由于内容原因于 4 | 被管理员移动到了 {{ nf.node.name }} 节点,请注意查看节点说明。 5 |

6 | 7 |
8 | -------------------------------------------------------------------------------- /www/templates/notifications/topic.html: -------------------------------------------------------------------------------- 1 | 2 | nf.actor.login 3 |

4 | {{ nf.actor.login }} 发布了新帖: 5 |

6 |
{{ nf.topic.title }}
7 | 8 |
9 | -------------------------------------------------------------------------------- /www/templates/notifications/topicreply.html: -------------------------------------------------------------------------------- 1 | 2 | nf.actor.login 3 |

4 | {{ nf.actor.login }} 于 5 | 在帖子中回复了: 6 |

7 |
{{ nf.topic.title }}
8 |
9 | 10 |
11 | -------------------------------------------------------------------------------- /www/templates/topic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 | {{ vm.topic.user.login }} 10 |

11 | {{ vm.topic.user.login }} 12 | 13 | {{ vm.topic.node_name }} 14 | {{ vm.topic.created_at | date: 'MM月dd日' }} 15 | 16 |

17 |
18 |
19 |

{{ vm.topic.title }}

20 |
21 |
22 |
23 |
24 | 25 |
26 | 27 | 28 | {{ vm.topic.likes_count }}> 个赞 29 | 30 | 31 | 32 | {{ vm.topic.replies_count }} 条回复 33 | 34 |
35 | 36 |
37 |
38 |
39 |
40 |
41 | {{ $index + 1 }} 楼已删除 42 |
43 |
44 | 45 |
46 | {{ reply.user.login }} 47 |

48 | {{ reply.user.login }} 49 | 50 | 51 | #{{ $index +1 }} 52 | {{ reply.created_at | date: 'MM月dd日' }} 53 | 54 |

55 |
56 | 57 |
58 |
59 | 60 |
61 |
62 |
63 |
64 | 65 | 66 | 67 | 68 |
69 |
70 |
71 |
72 | 73 | 74 |
75 | 76 | 77 |
78 | 79 |
80 | -------------------------------------------------------------------------------- /www/templates/topics.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 | 30 | 33 | {{ topic.user.login }} 34 |

{{ topic.title }}

35 |
{{ topic.node_name }} {{ topic.user.login }}
36 | {{ topic.replies_count }} 37 |
38 |
39 | 43 | 44 |
45 |
46 | -------------------------------------------------------------------------------- /www/templates/user/profile.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 |
8 |
9 | {{ vm.user.login }} 10 | {{ vm.user.level_name }} 13 |

{{ vm.user.name }}

14 |

15 | @{{ vm.user.login }} 16 |

17 |
18 |
19 |
20 |
21 | 24 |
25 |
26 | 29 |
30 |
31 |
32 | 44 |
45 | 46 | 第 {{ vm.user.id }} 位会员 47 | / {{ vm.user.location }} / 注册于 {{ vm.user.created_at | date: 'yyyy-MM-dd' }} 48 | 49 |
50 |
51 | 52 | 53 | {{ vm.user.email }} 54 | 55 |
56 | 57 | {{ vm.user.twitter }} 58 |
59 |
60 | 61 | {{ vm.user.website }} 62 |
63 |
64 |
65 | 66 | 发布的话题 67 | {{ vm.user.topics_count }} 68 |
69 |
70 | 71 | 收藏 72 | {{ vm.user.favorites_count }} 73 |
74 |
75 |
76 |
77 | --------------------------------------------------------------------------------